From 932496b5468f8fbc7a27c2bcfbb8bed56cc43068 Mon Sep 17 00:00:00 2001 From: Jonathan Watt Date: Thu, 8 May 2014 10:53:00 +0100 Subject: [PATCH] Bug 590790 part 2 - Add memory reporter for VectorImage's SVGDocumentWrapper's document. r=dholbert, r=njn, r=seth --- image/src/Image.h | 8 +++ image/src/ImageWrapper.h | 4 ++ image/src/RasterImage.h | 4 ++ image/src/VectorImage.cpp | 37 ++++++++++++- image/src/VectorImage.h | 2 + image/src/imgLoader.cpp | 95 +++++++++++++++++++++++++++----- xpcom/base/nsIMemoryReporter.idl | 2 +- 7 files changed, 135 insertions(+), 17 deletions(-) diff --git a/image/src/Image.h b/image/src/Image.h index 99fe6df6fd49..8eb91e767f3c 100644 --- a/image/src/Image.h +++ b/image/src/Image.h @@ -10,6 +10,7 @@ #include "imgIContainer.h" #include "imgStatusTracker.h" #include "ImageURL.h" +#include "nsStringFwd.h" class nsIRequest; class nsIInputStream; @@ -84,6 +85,13 @@ public: virtual size_t NonHeapSizeOfDecoded() const = 0; virtual size_t OutOfProcessSizeOfDecoded() const = 0; + /** + * Gets the size of the memory taken up for the parsed vector image's + * document (e.g. SVGDocument), and returns the document's URL via the + * aDocURL outparam. + */ + virtual size_t HeapSizeOfVectorImageDocument(nsACString* aDocURL = nullptr) const = 0; + virtual void IncrementAnimationConsumers() = 0; virtual void DecrementAnimationConsumers() = 0; #ifdef DEBUG diff --git a/image/src/ImageWrapper.h b/image/src/ImageWrapper.h index 6f7003ea32b4..b5dbfb0e75d7 100644 --- a/image/src/ImageWrapper.h +++ b/image/src/ImageWrapper.h @@ -35,6 +35,10 @@ public: virtual size_t NonHeapSizeOfDecoded() const MOZ_OVERRIDE; virtual size_t OutOfProcessSizeOfDecoded() const MOZ_OVERRIDE; + virtual size_t HeapSizeOfVectorImageDocument(nsACString* aDocURL = nullptr) const MOZ_OVERRIDE { + return mInnerImage->HeapSizeOfVectorImageDocument(aDocURL); + } + virtual void IncrementAnimationConsumers() MOZ_OVERRIDE; virtual void DecrementAnimationConsumers() MOZ_OVERRIDE; #ifdef DEBUG diff --git a/image/src/RasterImage.h b/image/src/RasterImage.h index 4f15605bb53c..8eb957ca14ae 100644 --- a/image/src/RasterImage.h +++ b/image/src/RasterImage.h @@ -181,6 +181,10 @@ public: virtual size_t NonHeapSizeOfDecoded() const; virtual size_t OutOfProcessSizeOfDecoded() const; + virtual size_t HeapSizeOfVectorImageDocument(nsACString* aDocURL = nullptr) const MOZ_OVERRIDE { + return 0; + } + /* Triggers discarding. */ void Discard(bool force = false); void ForceDiscard() { Discard(/* force = */ true); } diff --git a/image/src/VectorImage.cpp b/image/src/VectorImage.cpp index 4f773f6245ef..0b66124fb569 100644 --- a/image/src/VectorImage.cpp +++ b/image/src/VectorImage.cpp @@ -22,8 +22,10 @@ #include "nsMimeTypes.h" #include "nsPresContext.h" #include "nsRect.h" +#include "nsString.h" #include "nsStubDocumentObserver.h" #include "nsSVGEffects.h" // for nsSVGRenderingObserver +#include "nsWindowMemoryReporter.h" #include "Orientation.h" #include "SVGDocumentWrapper.h" #include "nsIDOMEventListener.h" @@ -359,28 +361,61 @@ VectorImage::HeapSizeOfSourceWithComputedFallback(mozilla::MallocSizeOf aMallocS // 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. + // If implementing this, we'll need to restructure our callers to make sure + // any amount we return is attributed to the vector images measure (i.e. + // "explicit/images/{content,chrome}/vector/{used,unused}/...") return 0; } size_t VectorImage::HeapSizeOfDecodedWithComputedFallback(mozilla::MallocSizeOf aMallocSizeOf) const { - // XXXdholbert TODO: return num bytes used by helper SVG doc. (bug 590790) + // If implementing this, we'll need to restructure our callers to make sure + // any amount we return is attributed to the vector images measure (i.e. + // "explicit/images/{content,chrome}/vector/{used,unused}/...") return 0; } size_t VectorImage::NonHeapSizeOfDecoded() const { + // If implementing this, we'll need to restructure our callers to make sure + // any amount we return is attributed to the vector images measure (i.e. + // "explicit/images/{content,chrome}/vector/{used,unused}/...") return 0; } size_t VectorImage::OutOfProcessSizeOfDecoded() const { + // If implementing this, we'll need to restructure our callers to make sure + // any amount we return is attributed to the vector images measure (i.e. + // "explicit/images/{content,chrome}/vector/{used,unused}/...") return 0; } +MOZ_DEFINE_MALLOC_SIZE_OF(WindowsMallocSizeOf); + +size_t +VectorImage::HeapSizeOfVectorImageDocument(nsACString* aDocURL) const +{ + nsIDocument* doc = mSVGDocumentWrapper->GetDocument(); + if (!doc) { + if (aDocURL) { + mURI->GetSpec(*aDocURL); + } + return 0; // No document, so no memory used for the document + } + + if (aDocURL) { + doc->GetDocumentURI()->GetSpec(*aDocURL); + } + + nsWindowSizes windowSizes(WindowsMallocSizeOf); + doc->DocAddSizeOfExcludingThis(&windowSizes); + return windowSizes.getTotalSize(); +} + nsresult VectorImage::OnImageDataComplete(nsIRequest* aRequest, nsISupports* aContext, diff --git a/image/src/VectorImage.h b/image/src/VectorImage.h index 96f4e1a26aab..4d8481923d5b 100644 --- a/image/src/VectorImage.h +++ b/image/src/VectorImage.h @@ -48,6 +48,8 @@ public: virtual size_t NonHeapSizeOfDecoded() const; virtual size_t OutOfProcessSizeOfDecoded() const; + virtual size_t HeapSizeOfVectorImageDocument(nsACString* aDocURL = nullptr) const MOZ_OVERRIDE; + virtual nsresult OnImageDataAvailable(nsIRequest* aRequest, nsISupports* aContext, nsIInputStream* aInStr, diff --git a/image/src/imgLoader.cpp b/image/src/imgLoader.cpp index 8e0d11f219c0..388dea7db101 100644 --- a/image/src/imgLoader.cpp +++ b/image/src/imgLoader.cpp @@ -75,56 +75,101 @@ public: NS_ENSURE_SUCCESS(rv, rv); \ } while (0) - REPORT("explicit/images/chrome/used/raw", + REPORT("explicit/images/chrome/raster/used/raw", KIND_HEAP, chrome.mUsedRaw, "Memory used by in-use chrome images (compressed data)."); - REPORT("explicit/images/chrome/used/uncompressed-heap", + REPORT("explicit/images/chrome/raster/used/uncompressed-heap", KIND_HEAP, chrome.mUsedUncompressedHeap, "Memory used by in-use chrome images (uncompressed data)."); - REPORT("explicit/images/chrome/used/uncompressed-nonheap", + REPORT("explicit/images/chrome/raster/used/uncompressed-nonheap", KIND_NONHEAP, chrome.mUsedUncompressedNonheap, "Memory used by in-use chrome images (uncompressed data)."); - REPORT("explicit/images/chrome/unused/raw", + REPORT("explicit/images/chrome/raster/unused/raw", KIND_HEAP, chrome.mUnusedRaw, "Memory used by not in-use chrome images (compressed data)."); - REPORT("explicit/images/chrome/unused/uncompressed-heap", + REPORT("explicit/images/chrome/raster/unused/uncompressed-heap", KIND_HEAP, chrome.mUnusedUncompressedHeap, "Memory used by not in-use chrome images (uncompressed data)."); - REPORT("explicit/images/chrome/unused/uncompressed-nonheap", + REPORT("explicit/images/chrome/raster/unused/uncompressed-nonheap", KIND_NONHEAP, chrome.mUnusedUncompressedNonheap, "Memory used by not in-use chrome images (uncompressed data)."); - REPORT("explicit/images/content/used/raw", + REPORT("explicit/images/content/raster/used/raw", KIND_HEAP, content.mUsedRaw, "Memory used by in-use content images (compressed data)."); - REPORT("explicit/images/content/used/uncompressed-heap", + REPORT("explicit/images/content/raster/used/uncompressed-heap", KIND_HEAP, content.mUsedUncompressedHeap, "Memory used by in-use content images (uncompressed data)."); - REPORT("explicit/images/content/used/uncompressed-nonheap", + REPORT("explicit/images/content/raster/used/uncompressed-nonheap", KIND_NONHEAP, content.mUsedUncompressedNonheap, "Memory used by in-use content images (uncompressed data)."); - REPORT("explicit/images/content/unused/raw", + REPORT("explicit/images/content/raster/unused/raw", KIND_HEAP, content.mUnusedRaw, "Memory used by not in-use content images (compressed data)."); - REPORT("explicit/images/content/unused/uncompressed-heap", + REPORT("explicit/images/content/raster/unused/uncompressed-heap", KIND_HEAP, content.mUnusedUncompressedHeap, "Memory used by not in-use content images (uncompressed data)."); - REPORT("explicit/images/content/unused/uncompressed-nonheap", + REPORT("explicit/images/content/raster/unused/uncompressed-nonheap", KIND_NONHEAP, content.mUnusedUncompressedNonheap, "Memory used by not in-use content images (uncompressed data)."); #undef REPORT +#define REPORT_VECTOR(_path, _uri, _amount, _desc) \ + do { \ + nsAutoCString path(NS_LITERAL_CSTRING(_path)); \ + path.Append("/("); \ + path.Append(_uri); \ + path.Append(")"); \ + nsresult rv; \ + rv = callback->Callback(EmptyCString(), path, \ + KIND_HEAP, UNITS_BYTES, _amount, \ + NS_LITERAL_CSTRING(_desc), closure); \ + NS_ENSURE_SUCCESS(rv, rv); \ + } while (0) + + for (uint32_t i = 0; i < chrome.mVectorImageDocInfo.Length(); i++) { + chrome.mVectorImageDocInfo[i].mURI.ReplaceChar('/', '\\'); + if (chrome.mVectorImageDocInfo[i].mUsed) { + REPORT_VECTOR("explicit/images/chrome/vector/used/documents", + chrome.mVectorImageDocInfo[i].mURI, + chrome.mVectorImageDocInfo[i].mSize, + "Memory used by in-use chrome vector images for their parsed vector documents."); + } else { + REPORT_VECTOR("explicit/images/chrome/vector/unused/documents", + chrome.mVectorImageDocInfo[i].mURI, + chrome.mVectorImageDocInfo[i].mSize, + "Memory used by not in-use chrome vector images for their parsed vector documents."); + } + } + + for (uint32_t i = 0; i < content.mVectorImageDocInfo.Length(); i++) { + content.mVectorImageDocInfo[i].mURI.ReplaceChar('/', '\\'); + if (content.mVectorImageDocInfo[i].mUsed) { + REPORT_VECTOR("explicit/images/content/vector/used/documents", + content.mVectorImageDocInfo[i].mURI, + content.mVectorImageDocInfo[i].mSize, + "Memory used by in-use content vector images for their parsed vector documents."); + } else { + REPORT_VECTOR("explicit/images/content/vector/unused/documents", + content.mVectorImageDocInfo[i].mURI, + content.mVectorImageDocInfo[i].mSize, + "Memory used by not in-use content vector images for their parsed vector documents."); + } + } + +#undef REPORT_VECTOR + return NS_OK; } @@ -150,6 +195,12 @@ public: private: nsTArray mKnownLoaders; + struct VectorImageDocInfo { + size_t mSize; + bool mUsed; + nsAutoCString mURI; + }; + struct AllSizes { size_t mUsedRaw; size_t mUsedUncompressedHeap; @@ -157,10 +208,18 @@ private: size_t mUnusedRaw; size_t mUnusedUncompressedHeap; size_t mUnusedUncompressedNonheap; + // The size of VectorImages' documents are recorded individually so that we + // can report on each SVG-as-an-image individually. + nsTArray mVectorImageDocInfo; - AllSizes() { - memset(this, 0, sizeof(*this)); - } + AllSizes() + : mUsedRaw(0) + , mUsedUncompressedHeap(0) + , mUsedUncompressedNonheap(0) + , mUnusedRaw(0) + , mUnusedUncompressedHeap(0) + , mUnusedUncompressedNonheap(0) + {} }; static PLDHashOperator EntryAllSizes(const nsACString&, @@ -184,6 +243,12 @@ private: image->HeapSizeOfDecodedWithComputedFallback(ImagesMallocSizeOf); sizes->mUsedUncompressedNonheap += image->NonHeapSizeOfDecoded(); } + VectorImageDocInfo vectInfo; + vectInfo.mSize = image->HeapSizeOfVectorImageDocument(&vectInfo.mURI); + if (!vectInfo.mURI.IsEmpty()) { + vectInfo.mUsed = !entry->HasNoProxies(); + sizes->mVectorImageDocInfo.AppendElement(vectInfo); + } } return PL_DHASH_NEXT; diff --git a/xpcom/base/nsIMemoryReporter.idl b/xpcom/base/nsIMemoryReporter.idl index 07dfc2ddcf94..5d98be5ed471 100644 --- a/xpcom/base/nsIMemoryReporter.idl +++ b/xpcom/base/nsIMemoryReporter.idl @@ -328,7 +328,7 @@ interface nsIMemoryReporterManager : nsISupports * {system,user} compartments in the main JS runtime. * * |imagesContentUsedUncompressed| (UNITS_BYTES) Memory used for decoded - * images in content. + * raster images in content. * * |storageSQLite| (UNITS_BYTES) Memory used by SQLite. *