From 8e4a491d49ef94b48e1a9590fd64ffb9c33edcff Mon Sep 17 00:00:00 2001 From: Seth Fowler Date: Tue, 28 Apr 2015 11:46:17 -0700 Subject: [PATCH] Bug 1157954 - Report each surface in the ImageLib SurfaceCache individually in about:memory. r=dholbert --- image/src/DynamicImage.cpp | 10 +-- image/src/DynamicImage.h | 4 +- image/src/FrameAnimator.cpp | 49 +++++++++--- image/src/FrameAnimator.h | 10 ++- image/src/Image.cpp | 40 ++++++++++ image/src/Image.h | 120 ++++++++++++++++++++++++++-- image/src/ImageWrapper.cpp | 8 +- image/src/ImageWrapper.h | 8 +- image/src/RasterImage.cpp | 12 ++- image/src/RasterImage.h | 4 +- image/src/SurfaceCache.cpp | 76 ++++++++++-------- image/src/SurfaceCache.h | 19 +++-- image/src/VectorImage.cpp | 8 +- image/src/VectorImage.h | 4 +- image/src/imgFrame.h | 2 +- image/src/imgLoader.cpp | 154 ++++++++++++++++-------------------- 16 files changed, 349 insertions(+), 179 deletions(-) diff --git a/image/src/DynamicImage.cpp b/image/src/DynamicImage.cpp index 6f405cdf773..bb1ea692744 100644 --- a/image/src/DynamicImage.cpp +++ b/image/src/DynamicImage.cpp @@ -42,12 +42,12 @@ DynamicImage::SizeOfSourceWithComputedFallback(MallocSizeOf aMallocSizeOf) const return 0; } -size_t -DynamicImage::SizeOfDecoded(gfxMemoryLocation aLocation, - MallocSizeOf aMallocSizeOf) const +void +DynamicImage::CollectSizeOfSurfaces(nsTArray& aCounters, + MallocSizeOf aMallocSizeOf) const { - // We don't know the answer since gfxDrawable doesn't expose this information. - return 0; + // We can't report anything useful because gfxDrawable doesn't expose this + // information. } void diff --git a/image/src/DynamicImage.h b/image/src/DynamicImage.h index 3c0ccecceb1..fbfa22bf3b5 100644 --- a/image/src/DynamicImage.h +++ b/image/src/DynamicImage.h @@ -36,8 +36,8 @@ public: virtual already_AddRefed GetProgressTracker() override; virtual size_t SizeOfSourceWithComputedFallback( MallocSizeOf aMallocSizeOf) const override; - virtual size_t SizeOfDecoded(gfxMemoryLocation aLocation, - MallocSizeOf aMallocSizeOf) const override; + virtual void CollectSizeOfSurfaces(nsTArray& aCounters, + MallocSizeOf aMallocSizeOf) const override; virtual void IncrementAnimationConsumers() override; virtual void DecrementAnimationConsumers() override; diff --git a/image/src/FrameAnimator.cpp b/image/src/FrameAnimator.cpp index aa9144c8a12..1589792ba17 100644 --- a/image/src/FrameAnimator.cpp +++ b/image/src/FrameAnimator.cpp @@ -317,20 +317,51 @@ FrameAnimator::GetTimeoutForFrame(uint32_t aFrameNum) const return data.mRawTimeout; } -size_t -FrameAnimator::SizeOfCompositingFrames(gfxMemoryLocation aLocation, - MallocSizeOf aMallocSizeOf) const +static void +DoCollectSizeOfCompositingSurfaces(const RawAccessFrameRef& aSurface, + SurfaceMemoryCounterType aType, + nsTArray& aCounters, + MallocSizeOf aMallocSizeOf) { - size_t n = 0; + // Concoct a SurfaceKey for this surface. + SurfaceKey key = RasterSurfaceKey(aSurface->GetImageSize(), + imgIContainer::DECODE_FLAGS_DEFAULT, + /* aFrameNum = */ 0); + // Create a counter for this surface. + SurfaceMemoryCounter counter(key, /* aIsLocked = */ true, aType); + + // Extract the surface's memory usage information. + size_t heap = aSurface + ->SizeOfExcludingThis(gfxMemoryLocation::IN_PROCESS_HEAP, aMallocSizeOf); + counter.Values().SetDecodedHeap(heap); + + size_t nonHeap = aSurface + ->SizeOfExcludingThis(gfxMemoryLocation::IN_PROCESS_NONHEAP, nullptr); + counter.Values().SetDecodedNonHeap(nonHeap); + + // Record it. + aCounters.AppendElement(counter); +} + +void +FrameAnimator::CollectSizeOfCompositingSurfaces( + nsTArray& aCounters, + MallocSizeOf aMallocSizeOf) const +{ if (mCompositingFrame) { - n += mCompositingFrame->SizeOfExcludingThis(aLocation, aMallocSizeOf); - } - if (mCompositingPrevFrame) { - n += mCompositingPrevFrame->SizeOfExcludingThis(aLocation, aMallocSizeOf); + DoCollectSizeOfCompositingSurfaces(mCompositingFrame, + SurfaceMemoryCounterType::COMPOSITING, + aCounters, + aMallocSizeOf); } - return n; + if (mCompositingPrevFrame) { + DoCollectSizeOfCompositingSurfaces(mCompositingPrevFrame, + SurfaceMemoryCounterType::COMPOSITING_PREV, + aCounters, + aMallocSizeOf); + } } RawAccessFrameRef diff --git a/image/src/FrameAnimator.h b/image/src/FrameAnimator.h index 70798271d05..e9c2c6f2205 100644 --- a/image/src/FrameAnimator.h +++ b/image/src/FrameAnimator.h @@ -148,8 +148,14 @@ public: void SetLoopCount(int32_t aLoopCount) { mLoopCount = aLoopCount; } int32_t LoopCount() const { return mLoopCount; } - size_t SizeOfCompositingFrames(gfxMemoryLocation aLocation, - MallocSizeOf aMallocSizeOf) const; + /** + * Collect an accounting of the memory occupied by the compositing surfaces we + * use during animation playback. All of the actual animation frames are + * stored in the SurfaceCache, so we don't need to report them here. + */ + void CollectSizeOfCompositingSurfaces(nsTArray& aCounters, + MallocSizeOf aMallocSizeOf) const; + private: // methods /** * Gets the length of a single loop of this image, in milliseconds. diff --git a/image/src/Image.cpp b/image/src/Image.cpp index 81e7664bf90..5f19a8165f1 100644 --- a/image/src/Image.cpp +++ b/image/src/Image.cpp @@ -12,6 +12,46 @@ namespace mozilla { namespace image { +/////////////////////////////////////////////////////////////////////////////// +// Memory Reporting +/////////////////////////////////////////////////////////////////////////////// + +ImageMemoryCounter::ImageMemoryCounter(Image* aImage, + MallocSizeOf aMallocSizeOf, + bool aIsUsed) + : mIsUsed(aIsUsed) +{ + MOZ_ASSERT(aImage); + + // Extract metadata about the image. + nsRefPtr imageURL(aImage->GetURI()); + if (imageURL) { + imageURL->GetSpec(mURI); + } + + int32_t width = 0; + int32_t height = 0; + aImage->GetWidth(&width); + aImage->GetHeight(&height); + mIntrinsicSize.SizeTo(width, height); + + mType = aImage->GetType(); + + // Populate memory counters for source and decoded data. + mValues.SetSource(aImage->SizeOfSourceWithComputedFallback(aMallocSizeOf)); + aImage->CollectSizeOfSurfaces(mSurfaces, aMallocSizeOf); + + // Compute totals. + for (const SurfaceMemoryCounter& surfaceCounter : mSurfaces) { + mValues += surfaceCounter.Values(); + } +} + + +/////////////////////////////////////////////////////////////////////////////// +// Image Base Types +/////////////////////////////////////////////////////////////////////////////// + // Constructor ImageResource::ImageResource(ImageURL* aURI) : mURI(aURI), diff --git a/image/src/Image.h b/image/src/Image.h index b54d519b13b..91f2009331c 100644 --- a/image/src/Image.h +++ b/image/src/Image.h @@ -10,9 +10,10 @@ #include "mozilla/TimeStamp.h" #include "gfx2DGlue.h" // for gfxMemoryLocation #include "imgIContainer.h" -#include "ProgressTracker.h" #include "ImageURL.h" #include "nsStringFwd.h" +#include "ProgressTracker.h" +#include "SurfaceCache.h" class nsIRequest; class nsIInputStream; @@ -20,6 +21,111 @@ class nsIInputStream; namespace mozilla { namespace image { +class Image; + +/////////////////////////////////////////////////////////////////////////////// +// Memory Reporting +/////////////////////////////////////////////////////////////////////////////// + +struct MemoryCounter +{ + MemoryCounter() + : mSource(0) + , mDecodedHeap(0) + , mDecodedNonHeap(0) + { } + + void SetSource(size_t aCount) { mSource = aCount; } + size_t Source() const { return mSource; } + void SetDecodedHeap(size_t aCount) { mDecodedHeap = aCount; } + size_t DecodedHeap() const { return mDecodedHeap; } + void SetDecodedNonHeap(size_t aCount) { mDecodedNonHeap = aCount; } + size_t DecodedNonHeap() const { return mDecodedNonHeap; } + + MemoryCounter& operator+=(const MemoryCounter& aOther) + { + mSource += aOther.mSource; + mDecodedHeap += aOther.mDecodedHeap; + mDecodedNonHeap += aOther.mDecodedNonHeap; + return *this; + } + +private: + size_t mSource; + size_t mDecodedHeap; + size_t mDecodedNonHeap; +}; + +enum class SurfaceMemoryCounterType +{ + NORMAL, + COMPOSITING, + COMPOSITING_PREV +}; + +struct SurfaceMemoryCounter +{ + SurfaceMemoryCounter(const SurfaceKey& aKey, + bool aIsLocked, + SurfaceMemoryCounterType aType = + SurfaceMemoryCounterType::NORMAL) + : mKey(aKey) + , mType(aType) + , mIsLocked(aIsLocked) + { } + + const SurfaceKey& Key() const { return mKey; } + Maybe& SubframeSize() { return mSubframeSize; } + const Maybe& SubframeSize() const { return mSubframeSize; } + MemoryCounter& Values() { return mValues; } + const MemoryCounter& Values() const { return mValues; } + SurfaceMemoryCounterType Type() const { return mType; } + bool IsLocked() const { return mIsLocked; } + +private: + const SurfaceKey mKey; + Maybe mSubframeSize; + MemoryCounter mValues; + const SurfaceMemoryCounterType mType; + const bool mIsLocked; +}; + +struct ImageMemoryCounter +{ + ImageMemoryCounter(Image* aImage, + MallocSizeOf aMallocSizeOf, + bool aIsUsed); + + nsCString& URI() { return mURI; } + const nsCString& URI() const { return mURI; } + const nsTArray& Surfaces() const { return mSurfaces; } + const gfx::IntSize IntrinsicSize() const { return mIntrinsicSize; } + const MemoryCounter& Values() const { return mValues; } + uint16_t Type() const { return mType; } + bool IsUsed() const { return mIsUsed; } + + bool IsNotable() const + { + const size_t NotableThreshold = 16 * 1024; + size_t total = mValues.Source() + mValues.DecodedHeap() + + mValues.DecodedNonHeap(); + return total >= NotableThreshold; + } + +private: + nsCString mURI; + nsTArray mSurfaces; + gfx::IntSize mIntrinsicSize; + MemoryCounter mValues; + uint16_t mType; + const bool mIsUsed; +}; + + +/////////////////////////////////////////////////////////////////////////////// +// Image Base Types +/////////////////////////////////////////////////////////////////////////////// + class Image : public imgIContainer { public: @@ -84,14 +190,16 @@ public: * If MallocSizeOf does not work on this platform, uses a fallback approach to * ensure that something reasonable is always returned. */ - virtual size_t SizeOfSourceWithComputedFallback( - MallocSizeOf aMallocSizeOf) const = 0; + virtual size_t + SizeOfSourceWithComputedFallback(MallocSizeOf aMallocSizeOf) const = 0; /** - * The size, in bytes, occupied by the image's decoded data. + * Collect an accounting of the memory occupied by the image's surfaces (which + * together make up its decoded data). Each surface is recorded as a separate + * SurfaceMemoryCounter, stored in @aCounters. */ - virtual size_t SizeOfDecoded(gfxMemoryLocation aLocation, - MallocSizeOf aMallocSizeOf) const = 0; + virtual void CollectSizeOfSurfaces(nsTArray& aCounters, + MallocSizeOf aMallocSizeOf) const = 0; virtual void IncrementAnimationConsumers() = 0; virtual void DecrementAnimationConsumers() = 0; diff --git a/image/src/ImageWrapper.cpp b/image/src/ImageWrapper.cpp index f9695e4aa6e..926c28fde27 100644 --- a/image/src/ImageWrapper.cpp +++ b/image/src/ImageWrapper.cpp @@ -39,11 +39,11 @@ ImageWrapper::SizeOfSourceWithComputedFallback(MallocSizeOf aMallocSizeOf) const return mInnerImage->SizeOfSourceWithComputedFallback(aMallocSizeOf); } -size_t -ImageWrapper::SizeOfDecoded(gfxMemoryLocation aLocation, - MallocSizeOf aMallocSizeOf) const +void +ImageWrapper::CollectSizeOfSurfaces(nsTArray& aCounters, + MallocSizeOf aMallocSizeOf) const { - return mInnerImage->SizeOfDecoded(aLocation, aMallocSizeOf); + mInnerImage->CollectSizeOfSurfaces(aCounters, aMallocSizeOf); } void diff --git a/image/src/ImageWrapper.h b/image/src/ImageWrapper.h index b9016009607..28ce7afa80d 100644 --- a/image/src/ImageWrapper.h +++ b/image/src/ImageWrapper.h @@ -27,11 +27,9 @@ public: virtual already_AddRefed GetProgressTracker() override; virtual size_t - SizeOfSourceWithComputedFallback( MallocSizeOf aMallocSizeOf) const - override; - virtual size_t - SizeOfDecoded(gfxMemoryLocation aLocation, - MallocSizeOf aMallocSizeOf) const override; + SizeOfSourceWithComputedFallback(MallocSizeOf aMallocSizeOf) const override; + virtual void CollectSizeOfSurfaces(nsTArray& aCounters, + MallocSizeOf aMallocSizeOf) const override; virtual void IncrementAnimationConsumers() override; virtual void DecrementAnimationConsumers() override; diff --git a/image/src/RasterImage.cpp b/image/src/RasterImage.cpp index 194283af728..34b428911bf 100644 --- a/image/src/RasterImage.cpp +++ b/image/src/RasterImage.cpp @@ -888,16 +888,14 @@ RasterImage::SizeOfSourceWithComputedFallback(MallocSizeOf aMallocSizeOf) const return mSourceBuffer->SizeOfIncludingThisWithComputedFallback(aMallocSizeOf); } -size_t -RasterImage::SizeOfDecoded(gfxMemoryLocation aLocation, - MallocSizeOf aMallocSizeOf) const +void +RasterImage::CollectSizeOfSurfaces(nsTArray& aCounters, + MallocSizeOf aMallocSizeOf) const { - size_t n = 0; - n += SurfaceCache::SizeOfSurfaces(ImageKey(this), aLocation, aMallocSizeOf); + SurfaceCache::CollectSizeOfSurfaces(ImageKey(this), aCounters, aMallocSizeOf); if (mAnim) { - n += mAnim->SizeOfCompositingFrames(aLocation, aMallocSizeOf); + mAnim->CollectSizeOfCompositingSurfaces(aCounters, aMallocSizeOf); } - return n; } class OnAddedFrameRunnable : public nsRunnable diff --git a/image/src/RasterImage.h b/image/src/RasterImage.h index 40bc62b05f4..f516ef48cce 100644 --- a/image/src/RasterImage.h +++ b/image/src/RasterImage.h @@ -182,8 +182,8 @@ public: virtual size_t SizeOfSourceWithComputedFallback(MallocSizeOf aMallocSizeOf) const override; - virtual size_t SizeOfDecoded(gfxMemoryLocation aLocation, - MallocSizeOf aMallocSizeOf) const override; + virtual void CollectSizeOfSurfaces(nsTArray& aCounters, + MallocSizeOf aMallocSizeOf) const override; /* Triggers discarding. */ void Discard(); diff --git a/image/src/SurfaceCache.cpp b/image/src/SurfaceCache.cpp index d0b8e3b7e21..ca50a93280a 100644 --- a/image/src/SurfaceCache.cpp +++ b/image/src/SurfaceCache.cpp @@ -164,33 +164,41 @@ public: Lifetime GetLifetime() const { return mLifetime; } bool IsDecoded() const { return mSurface->IsImageComplete(); } - // A helper type used by SurfaceCacheImpl::SizeOfSurfacesSum. - struct SizeOfSurfacesSum + // A helper type used by SurfaceCacheImpl::CollectSizeOfSurfaces. + struct MOZ_STACK_CLASS SurfaceMemoryReport { - SizeOfSurfacesSum(gfxMemoryLocation aLocation, - MallocSizeOf aMallocSizeOf) - : mLocation(aLocation) + SurfaceMemoryReport(nsTArray& aCounters, + MallocSizeOf aMallocSizeOf) + : mCounters(aCounters) , mMallocSizeOf(aMallocSizeOf) - , mSum(0) { } void Add(CachedSurface* aCachedSurface) { MOZ_ASSERT(aCachedSurface, "Should have a CachedSurface"); - if (!aCachedSurface->mSurface) { - return; + SurfaceMemoryCounter counter(aCachedSurface->GetSurfaceKey(), + aCachedSurface->IsLocked()); + + if (aCachedSurface->mSurface) { + counter.SubframeSize() = Some(aCachedSurface->mSurface->GetSize()); + + size_t heap = aCachedSurface->mSurface + ->SizeOfExcludingThis(gfxMemoryLocation::IN_PROCESS_HEAP, + mMallocSizeOf); + counter.Values().SetDecodedHeap(heap); + + size_t nonHeap = aCachedSurface->mSurface + ->SizeOfExcludingThis(gfxMemoryLocation::IN_PROCESS_NONHEAP, nullptr); + counter.Values().SetDecodedNonHeap(nonHeap); } - mSum += aCachedSurface->mSurface->SizeOfExcludingThis(mLocation, - mMallocSizeOf); + + mCounters.AppendElement(counter); } - size_t Result() const { return mSum; } - private: - gfxMemoryLocation mLocation; - MallocSizeOf mMallocSizeOf; - size_t mSum; + nsTArray& mCounters; + MallocSizeOf mMallocSizeOf; }; private: @@ -789,28 +797,26 @@ public: return NS_OK; } - size_t SizeOfSurfaces(const ImageKey aImageKey, - gfxMemoryLocation aLocation, - MallocSizeOf aMallocSizeOf) + void CollectSizeOfSurfaces(const ImageKey aImageKey, + nsTArray& aCounters, + MallocSizeOf aMallocSizeOf) { nsRefPtr cache = GetImageCache(aImageKey); if (!cache) { - return 0; // No surfaces for this image. + return; // No surfaces for this image. } - // Sum the size of all surfaces in the per-image cache. - CachedSurface::SizeOfSurfacesSum sum(aLocation, aMallocSizeOf); - cache->ForEach(DoSizeOfSurfacesSum, &sum); - - return sum.Result(); + // Report all surfaces in the per-image cache. + CachedSurface::SurfaceMemoryReport report(aCounters, aMallocSizeOf); + cache->ForEach(DoCollectSizeOfSurface, &report); } - static PLDHashOperator DoSizeOfSurfacesSum(const SurfaceKey&, - CachedSurface* aSurface, - void* aSum) + static PLDHashOperator DoCollectSizeOfSurface(const SurfaceKey&, + CachedSurface* aSurface, + void* aReport) { - auto sum = static_cast(aSum); - sum->Add(aSurface); + auto report = static_cast(aReport); + report->Add(aSurface); return PL_DHASH_NEXT; } @@ -1075,17 +1081,17 @@ SurfaceCache::DiscardAll() } } -/* static */ size_t -SurfaceCache::SizeOfSurfaces(const ImageKey aImageKey, - gfxMemoryLocation aLocation, - MallocSizeOf aMallocSizeOf) +/* static */ void +SurfaceCache::CollectSizeOfSurfaces(const ImageKey aImageKey, + nsTArray& aCounters, + MallocSizeOf aMallocSizeOf) { if (!sInstance) { - return 0; + return; } MutexAutoLock lock(sInstance->GetMutex()); - return sInstance->SizeOfSurfaces(aImageKey, aLocation, aMallocSizeOf); + return sInstance->CollectSizeOfSurfaces(aImageKey, aCounters, aMallocSizeOf); } } // namespace image diff --git a/image/src/SurfaceCache.h b/image/src/SurfaceCache.h index b65bb1be449..3107c293869 100644 --- a/image/src/SurfaceCache.h +++ b/image/src/SurfaceCache.h @@ -27,6 +27,7 @@ namespace image { class DrawableFrameRef; class Image; class imgFrame; +struct SurfaceMemoryCounter; /* * ImageKey contains the information we need to look up all cached surfaces for @@ -392,21 +393,19 @@ struct SurfaceCache static void DiscardAll(); /** - * Computes the size of the surfaces stored for the given image at the given - * memory location. + * Collects an accounting of the surfaces contained in the SurfaceCache for + * the given image, along with their size and various other metadata. * * This is intended for use with memory reporting. * * @param aImageKey The image to report memory usage for. - * @param aLocation The location (heap, nonheap, etc.) of the memory to - * report on. - * @param aMallocSizeOf A fallback malloc memory reporting function. This - * should be null unless we're reporting on in-process - * heap memory. + * @param aCounters An array into which the report for each surface will + * be written. + * @param aMallocSizeOf A fallback malloc memory reporting function. */ - static size_t SizeOfSurfaces(const ImageKey aImageKey, - gfxMemoryLocation aLocation, - MallocSizeOf aMallocSizeOf); + static void CollectSizeOfSurfaces(const ImageKey aImageKey, + nsTArray& aCounters, + MallocSizeOf aMallocSizeOf); private: virtual ~SurfaceCache() = 0; // Forbid instantiation. diff --git a/image/src/VectorImage.cpp b/image/src/VectorImage.cpp index 005fab0d7cd..eb0550a4be6 100644 --- a/image/src/VectorImage.cpp +++ b/image/src/VectorImage.cpp @@ -397,11 +397,11 @@ VectorImage::SizeOfSourceWithComputedFallback(MallocSizeOf aMallocSizeOf) const return windowSizes.getTotalSize(); } -size_t -VectorImage::SizeOfDecoded(gfxMemoryLocation aLocation, - MallocSizeOf aMallocSizeOf) const +void +VectorImage::CollectSizeOfSurfaces(nsTArray& aCounters, + MallocSizeOf aMallocSizeOf) const { - return SurfaceCache::SizeOfSurfaces(ImageKey(this), aLocation, aMallocSizeOf); + SurfaceCache::CollectSizeOfSurfaces(ImageKey(this), aCounters, aMallocSizeOf); } nsresult diff --git a/image/src/VectorImage.h b/image/src/VectorImage.h index 3282fbe6c6a..4032d6ed677 100644 --- a/image/src/VectorImage.h +++ b/image/src/VectorImage.h @@ -39,8 +39,8 @@ public: virtual size_t SizeOfSourceWithComputedFallback(MallocSizeOf aMallocSizeOf) const override; - virtual size_t SizeOfDecoded(gfxMemoryLocation aLocation, - MallocSizeOf aMallocSizeOf) const override; + virtual void CollectSizeOfSurfaces(nsTArray& aCounters, + MallocSizeOf aMallocSizeOf) const override; virtual nsresult OnImageDataAvailable(nsIRequest* aRequest, nsISupports* aContext, diff --git a/image/src/imgFrame.h b/image/src/imgFrame.h index 027f8c73c8e..24c22d44221 100644 --- a/image/src/imgFrame.h +++ b/image/src/imgFrame.h @@ -236,7 +236,7 @@ public: */ void WaitUntilComplete() const; - IntSize GetImageSize() { return mImageSize; } + IntSize GetImageSize() const { return mImageSize; } nsIntRect GetRect() const; IntSize GetSize() const { return mSize; } bool NeedsPadding() const { return mOffset != nsIntPoint(0, 0); } diff --git a/image/src/imgLoader.cpp b/image/src/imgLoader.cpp index 3c24cdf71ef..977ce20be04 100644 --- a/image/src/imgLoader.cpp +++ b/image/src/imgLoader.cpp @@ -117,67 +117,6 @@ public: private: nsTArray mKnownLoaders; - struct MemoryCounter - { - MemoryCounter() - : mSource(0) - , mDecodedHeap(0) - , mDecodedNonHeap(0) - { } - - void SetSource(size_t aCount) { mSource = aCount; } - size_t Source() const { return mSource; } - void SetDecodedHeap(size_t aCount) { mDecodedHeap = aCount; } - size_t DecodedHeap() const { return mDecodedHeap; } - void SetDecodedNonHeap(size_t aCount) { mDecodedNonHeap = aCount; } - size_t DecodedNonHeap() const { return mDecodedNonHeap; } - - MemoryCounter& operator+=(const MemoryCounter& aOther) - { - mSource += aOther.mSource; - mDecodedHeap += aOther.mDecodedHeap; - mDecodedNonHeap += aOther.mDecodedNonHeap; - return *this; - } - - private: - size_t mSource; - size_t mDecodedHeap; - size_t mDecodedNonHeap; - }; - - struct ImageMemoryCounter - { - ImageMemoryCounter(uint16_t aType, const nsACString& aURI, bool aIsUsed) - : mURI(aURI) - , mType(aType) - , mIsUsed(aIsUsed) - { - MOZ_ASSERT(!mURI.IsEmpty(), "Should have a URI for all images"); - } - - nsCString& URI() { return mURI; } - const nsCString& URI() const { return mURI; } - uint16_t Type() const { return mType; } - MemoryCounter& Values() { return mValues; } - const MemoryCounter& Values() const { return mValues; } - bool IsUsed() const { return mIsUsed; } - - bool IsNotable() const - { - const size_t NotableThreshold = 16 * 1024; - size_t total = mValues.Source() + mValues.DecodedHeap() - + mValues.DecodedNonHeap(); - return total >= NotableThreshold; - } - - private: - nsCString mURI; - uint16_t mType; - MemoryCounter mValues; - bool mIsUsed; - }; - struct MemoryTotal { MemoryTotal& operator+=(const ImageMemoryCounter& aImageCounter) @@ -216,7 +155,7 @@ private: // Reports all images of a single kind, e.g. all used chrome images. nsresult ReportCounterArray(nsIHandleReportCallback* aHandleReport, nsISupports* aData, - const nsTArray& aCounterArray, + nsTArray& aCounterArray, const char* aPathPrefix, bool aAnonymize = false) { @@ -226,7 +165,7 @@ private: // Report notable images, and compute total and non-notable aggregate sizes. for (uint32_t i = 0; i < aCounterArray.Length(); i++) { - ImageMemoryCounter counter = aCounterArray[i]; + ImageMemoryCounter& counter = aCounterArray[i]; if (aAnonymize) { counter.URI().Truncate(); @@ -244,7 +183,7 @@ private: summaryTotal += counter; if (counter.IsNotable()) { - rv = ReportCounter(aHandleReport, aData, aPathPrefix, counter); + rv = ReportImage(aHandleReport, aData, aPathPrefix, counter); NS_ENSURE_SUCCESS(rv, rv); } else { nonNotableTotal += counter; @@ -264,10 +203,10 @@ private: return NS_OK; } - static nsresult ReportCounter(nsIHandleReportCallback* aHandleReport, - nsISupports* aData, - const char* aPathPrefix, - const ImageMemoryCounter& aCounter) + static nsresult ReportImage(nsIHandleReportCallback* aHandleReport, + nsISupports* aData, + const char* aPathPrefix, + const ImageMemoryCounter& aCounter) { nsAutoCString pathPrefix(NS_LITERAL_CSTRING("explicit/")); pathPrefix.Append(aPathPrefix); @@ -276,14 +215,68 @@ private: : "/vector/"); pathPrefix.Append(aCounter.IsUsed() ? "used/" : "unused/"); pathPrefix.Append("image("); + pathPrefix.AppendInt(aCounter.IntrinsicSize().width); + pathPrefix.Append("x"); + pathPrefix.AppendInt(aCounter.IntrinsicSize().height); + pathPrefix.Append(", "); + if (aCounter.URI().IsEmpty()) { pathPrefix.Append(""); } else { pathPrefix.Append(aCounter.URI()); } + pathPrefix.Append(")/"); - return ReportValues(aHandleReport, aData, pathPrefix, aCounter.Values()); + return ReportSurfaces(aHandleReport, aData, pathPrefix, aCounter); + } + + static nsresult ReportSurfaces(nsIHandleReportCallback* aHandleReport, + nsISupports* aData, + const nsACString& aPathPrefix, + const ImageMemoryCounter& aCounter) + { + for (const SurfaceMemoryCounter& counter : aCounter.Surfaces()) { + nsAutoCString surfacePathPrefix(aPathPrefix); + surfacePathPrefix.Append(counter.IsLocked() ? "locked/" : "unlocked/"); + surfacePathPrefix.Append("surface("); + + if (counter.SubframeSize() && + *counter.SubframeSize() != counter.Key().Size()) { + surfacePathPrefix.AppendInt(counter.SubframeSize()->width); + surfacePathPrefix.Append("x"); + surfacePathPrefix.AppendInt(counter.SubframeSize()->height); + surfacePathPrefix.Append(" subframe of "); + } + + surfacePathPrefix.AppendInt(counter.Key().Size().width); + surfacePathPrefix.Append("x"); + surfacePathPrefix.AppendInt(counter.Key().Size().height); + + if (counter.Type() == SurfaceMemoryCounterType::NORMAL) { + surfacePathPrefix.Append("@"); + surfacePathPrefix.AppendFloat(counter.Key().AnimationTime()); + + if (counter.Key().Flags() != imgIContainer::DECODE_FLAGS_DEFAULT) { + surfacePathPrefix.Append(", flags:"); + surfacePathPrefix.AppendInt(counter.Key().Flags(), /* aRadix = */ 16); + } + } else if (counter.Type() == SurfaceMemoryCounterType::COMPOSITING) { + surfacePathPrefix.Append(", compositing frame"); + } else if (counter.Type() == SurfaceMemoryCounterType::COMPOSITING_PREV) { + surfacePathPrefix.Append(", compositing prev frame"); + } else { + MOZ_ASSERT_UNREACHABLE("Unknown counter type"); + } + + surfacePathPrefix.Append(")/"); + + nsresult rv = ReportValues(aHandleReport, aData, surfacePathPrefix, + counter.Values()); + NS_ENSURE_SUCCESS(rv, rv); + } + + return NS_OK; } static nsresult ReportTotal(nsIHandleReportCallback* aHandleReport, @@ -410,20 +403,9 @@ private: return; } - nsRefPtr imageURL(image->GetURI()); - nsAutoCString spec; - imageURL->GetSpec(spec); + ImageMemoryCounter counter(image, ImagesMallocSizeOf, aIsUsed); - ImageMemoryCounter counter(image->GetType(), spec, aIsUsed); - - counter.Values().SetSource(image-> - SizeOfSourceWithComputedFallback(ImagesMallocSizeOf)); - counter.Values().SetDecodedHeap(image-> - SizeOfDecoded(gfxMemoryLocation::IN_PROCESS_HEAP, ImagesMallocSizeOf)); - counter.Values().SetDecodedNonHeap(image-> - SizeOfDecoded(gfxMemoryLocation::IN_PROCESS_NONHEAP, nullptr)); - - aArray->AppendElement(counter); + aArray->AppendElement(Move(counter)); } static PLDHashOperator DoRecordCounterUsedDecoded(const ImageCacheKey&, @@ -444,10 +426,12 @@ private: // memory. This function's measurement is secondary -- the result doesn't // go in the "explicit" tree -- so we use moz_malloc_size_of instead of // ImagesMallocSizeOf to prevent DMD from seeing it reported twice. + ImageMemoryCounter counter(image, moz_malloc_size_of, /* aIsUsed = */ true); + auto n = static_cast(aUserArg); - *n += image->SizeOfDecoded(gfxMemoryLocation::IN_PROCESS_HEAP, - moz_malloc_size_of); - *n += image->SizeOfDecoded(gfxMemoryLocation::IN_PROCESS_NONHEAP, nullptr); + *n += counter.Values().DecodedHeap(); + *n += counter.Values().DecodedNonHeap(); + return PL_DHASH_NEXT; } };