Backed out changeset 2d6db5d2f985 (bug 1065818) for Android Crashes

This commit is contained in:
Carsten "Tomcat" Book 2014-11-25 12:40:24 +01:00
parent 0bcfff8103
commit d003fee1b3
19 changed files with 528 additions and 370 deletions

View File

@ -43,17 +43,41 @@ DynamicImage::FrameRect(uint32_t aWhichFrame)
return nsIntRect(0, 0, size.width, size.height);
}
uint32_t
DynamicImage::SizeOfData()
{
// We don't know the answer to this (and the same goes for the other
// memory-related methods) since gfxDrawable doesn't expose a way to check.
return 0;
}
size_t
DynamicImage::SizeOfSourceWithComputedFallback(MallocSizeOf aMallocSizeOf) const
DynamicImage::HeapSizeOfSourceWithComputedFallback(mozilla::MallocSizeOf aMallocSizeOf) const
{
return 0;
}
size_t
DynamicImage::SizeOfDecoded(gfxMemoryLocation aLocation,
MallocSizeOf aMallocSizeOf) const
DynamicImage::HeapSizeOfDecodedWithComputedFallback(mozilla::MallocSizeOf aMallocSizeOf) const
{
return 0;
}
size_t
DynamicImage::NonHeapSizeOfDecoded() const
{
return 0;
}
size_t
DynamicImage::OutOfProcessSizeOfDecoded() const
{
return 0;
}
size_t
DynamicImage::HeapSizeOfVectorImageDocument(nsACString* aDocURL) const
{
// We don't know the answer since gfxDrawable doesn't expose this information.
return 0;
}

View File

@ -37,9 +37,12 @@ public:
virtual already_AddRefed<ProgressTracker> GetProgressTracker() MOZ_OVERRIDE;
virtual nsIntRect FrameRect(uint32_t aWhichFrame) MOZ_OVERRIDE;
virtual size_t SizeOfSourceWithComputedFallback(MallocSizeOf aMallocSizeOf) const MOZ_OVERRIDE;
virtual size_t SizeOfDecoded(gfxMemoryLocation aLocation,
MallocSizeOf aMallocSizeOf) const MOZ_OVERRIDE;
virtual uint32_t SizeOfData() MOZ_OVERRIDE;
virtual size_t HeapSizeOfSourceWithComputedFallback(mozilla::MallocSizeOf aMallocSizeOf) const MOZ_OVERRIDE;
virtual size_t HeapSizeOfDecodedWithComputedFallback(mozilla::MallocSizeOf aMallocSizeOf) const MOZ_OVERRIDE;
virtual size_t NonHeapSizeOfDecoded() const MOZ_OVERRIDE;
virtual size_t OutOfProcessSizeOfDecoded() const MOZ_OVERRIDE;
virtual size_t HeapSizeOfVectorImageDocument(nsACString* aDocURL = nullptr) const MOZ_OVERRIDE;
virtual void IncrementAnimationConsumers() MOZ_OVERRIDE;
virtual void DecrementAnimationConsumers() MOZ_OVERRIDE;

View File

@ -563,23 +563,26 @@ FrameBlender::Discard()
}
size_t
FrameBlender::SizeOfDecoded(gfxMemoryLocation aLocation,
MallocSizeOf aMallocSizeOf) const
FrameBlender::SizeOfDecodedWithComputedFallbackIfHeap(gfxMemoryLocation aLocation,
MallocSizeOf aMallocSizeOf) const
{
size_t n = 0;
for (uint32_t i = 0; i < mFrames.Length(); ++i) {
n += mFrames[i]->SizeOfExcludingThis(aLocation, aMallocSizeOf);
n += mFrames[i]->SizeOfExcludingThisWithComputedFallbackIfHeap(aLocation,
aMallocSizeOf);
}
if (mAnim) {
if (mAnim->compositingFrame) {
n += mAnim->compositingFrame
->SizeOfExcludingThis(aLocation, aMallocSizeOf);
->SizeOfExcludingThisWithComputedFallbackIfHeap(aLocation,
aMallocSizeOf);
}
if (mAnim->compositingPrevFrame) {
n += mAnim->compositingPrevFrame
->SizeOfExcludingThis(aLocation, aMallocSizeOf);
->SizeOfExcludingThisWithComputedFallbackIfHeap(aLocation,
aMallocSizeOf);
}
}

View File

@ -72,8 +72,8 @@ public:
void SetSize(nsIntSize aSize) { mSize = aSize; }
size_t SizeOfDecoded(gfxMemoryLocation aLocation,
MallocSizeOf aMallocSizeOf) const;
size_t SizeOfDecodedWithComputedFallbackIfHeap(gfxMemoryLocation aLocation,
MallocSizeOf aMallocSizeOf) const;
void ResetAnimation();

View File

@ -24,6 +24,21 @@ ImageResource::ImageResource(ImageURL* aURI) :
{
}
uint32_t
ImageResource::SizeOfData()
{
if (mError)
return 0;
// This is not used by memory reporters, but for sizing the cache, which is
// why it uses |moz_malloc_size_of| rather than a
// |MOZ_DEFINE_MALLOC_SIZE_OF|.
return uint32_t(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)

View File

@ -7,7 +7,6 @@
#define MOZILLA_IMAGELIB_IMAGE_H_
#include "mozilla/MemoryReporting.h"
#include "gfx2DGlue.h" // for gfxMemoryLocation
#include "imgIContainer.h"
#include "ProgressTracker.h"
#include "ImageURL.h"
@ -73,17 +72,25 @@ public:
virtual nsIntRect FrameRect(uint32_t aWhichFrame) = 0;
/**
* The size, in bytes, occupied by the compressed source data of the image.
* If MallocSizeOf does not work on this platform, uses a fallback approach to
* ensure that something reasonable is always returned.
* The size, in bytes, occupied by the significant data portions of the image.
* This includes both compressed source data and decoded frames.
*/
virtual size_t SizeOfSourceWithComputedFallback(MallocSizeOf aMallocSizeOf) const = 0;
virtual uint32_t SizeOfData() = 0;
/**
* The size, in bytes, occupied by the image's decoded data.
* The components that make up SizeOfData().
*/
virtual size_t SizeOfDecoded(gfxMemoryLocation aLocation,
MallocSizeOf aMallocSizeOf) const = 0;
virtual size_t HeapSizeOfSourceWithComputedFallback(MallocSizeOf aMallocSizeOf) const = 0;
virtual size_t HeapSizeOfDecodedWithComputedFallback(MallocSizeOf aMallocSizeOf) const = 0;
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;
@ -149,6 +156,7 @@ public:
MOZ_ASSERT(!mProgressTracker);
mProgressTracker = aProgressTracker;
}
virtual uint32_t SizeOfData() MOZ_OVERRIDE;
virtual void IncrementAnimationConsumers() MOZ_OVERRIDE;
virtual void DecrementAnimationConsumers() MOZ_OVERRIDE;

View File

@ -39,17 +39,34 @@ ImageWrapper::FrameRect(uint32_t aWhichFrame)
return mInnerImage->FrameRect(aWhichFrame);
}
size_t
ImageWrapper::SizeOfSourceWithComputedFallback(MallocSizeOf aMallocSizeOf) const
uint32_t
ImageWrapper::SizeOfData()
{
return mInnerImage->SizeOfSourceWithComputedFallback(aMallocSizeOf);
return mInnerImage->SizeOfData();
}
size_t
ImageWrapper::SizeOfDecoded(gfxMemoryLocation aLocation,
MallocSizeOf aMallocSizeOf) const
ImageWrapper::HeapSizeOfSourceWithComputedFallback(MallocSizeOf aMallocSizeOf) const
{
return mInnerImage->SizeOfDecoded(aLocation, aMallocSizeOf);
return mInnerImage->HeapSizeOfSourceWithComputedFallback(aMallocSizeOf);
}
size_t
ImageWrapper::HeapSizeOfDecodedWithComputedFallback(MallocSizeOf aMallocSizeOf) const
{
return mInnerImage->HeapSizeOfDecodedWithComputedFallback(aMallocSizeOf);
}
size_t
ImageWrapper::NonHeapSizeOfDecoded() const
{
return mInnerImage->NonHeapSizeOfDecoded();
}
size_t
ImageWrapper::OutOfProcessSizeOfDecoded() const
{
return mInnerImage->OutOfProcessSizeOfDecoded();
}
void

View File

@ -27,8 +27,15 @@ public:
virtual already_AddRefed<ProgressTracker> GetProgressTracker() MOZ_OVERRIDE;
virtual nsIntRect FrameRect(uint32_t aWhichFrame) MOZ_OVERRIDE;
virtual size_t SizeOfSourceWithComputedFallback(MallocSizeOf aMallocSizeOf) const MOZ_OVERRIDE;
virtual size_t SizeOfDecoded(gfxMemoryLocation aLocation, MallocSizeOf aMallocSizeOf) const MOZ_OVERRIDE;
virtual uint32_t SizeOfData() MOZ_OVERRIDE;
virtual size_t HeapSizeOfSourceWithComputedFallback(MallocSizeOf aMallocSizeOf) const MOZ_OVERRIDE;
virtual size_t HeapSizeOfDecodedWithComputedFallback(MallocSizeOf aMallocSizeOf) const MOZ_OVERRIDE;
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;

View File

@ -964,7 +964,7 @@ RasterImage::UpdateImageContainer()
}
size_t
RasterImage::SizeOfSourceWithComputedFallback(MallocSizeOf aMallocSizeOf) const
RasterImage::HeapSizeOfSourceWithComputedFallback(MallocSizeOf aMallocSizeOf) const
{
// n == 0 is possible for two reasons.
// - This is a zero-length image.
@ -978,17 +978,39 @@ RasterImage::SizeOfSourceWithComputedFallback(MallocSizeOf aMallocSizeOf) const
}
size_t
RasterImage::SizeOfDecoded(gfxMemoryLocation aLocation,
MallocSizeOf aMallocSizeOf) const
RasterImage::SizeOfDecodedWithComputedFallbackIfHeap(gfxMemoryLocation aLocation,
MallocSizeOf aMallocSizeOf) const
{
size_t n = 0;
n += SurfaceCache::SizeOfSurfaces(ImageKey(this), aLocation, aMallocSizeOf);
if (mFrameBlender) {
n += mFrameBlender->SizeOfDecoded(aLocation, aMallocSizeOf);
n += mFrameBlender->SizeOfDecodedWithComputedFallbackIfHeap(aLocation,
aMallocSizeOf);
}
return n;
}
size_t
RasterImage::HeapSizeOfDecodedWithComputedFallback(MallocSizeOf aMallocSizeOf) const
{
return SizeOfDecodedWithComputedFallbackIfHeap(gfxMemoryLocation::IN_PROCESS_HEAP,
aMallocSizeOf);
}
size_t
RasterImage::NonHeapSizeOfDecoded() const
{
return SizeOfDecodedWithComputedFallbackIfHeap(gfxMemoryLocation::IN_PROCESS_NONHEAP,
nullptr);
}
size_t
RasterImage::OutOfProcessSizeOfDecoded() const
{
return SizeOfDecodedWithComputedFallbackIfHeap(gfxMemoryLocation::OUT_OF_PROCESS,
nullptr);
}
RawAccessFrameRef
RasterImage::InternalAddFrame(uint32_t aFrameNum,
const nsIntRect& aFrameRect,

View File

@ -171,9 +171,14 @@ public:
/* The total number of frames in this image. */
uint32_t GetNumFrames() const;
virtual size_t SizeOfSourceWithComputedFallback(MallocSizeOf aMallocSizeOf) const;
virtual size_t SizeOfDecoded(gfxMemoryLocation aLocation,
MallocSizeOf aMallocSizeOf) const;
virtual size_t HeapSizeOfSourceWithComputedFallback(MallocSizeOf aMallocSizeOf) const;
virtual size_t HeapSizeOfDecodedWithComputedFallback(MallocSizeOf aMallocSizeOf) const;
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 aForce = false, bool aNotify = true);

View File

@ -175,8 +175,9 @@ public:
if (!aCachedSurface->mSurface) {
return;
}
mSum += aCachedSurface->mSurface->SizeOfExcludingThis(mLocation,
mMallocSizeOf);
mSum += aCachedSurface->mSurface->
SizeOfExcludingThisWithComputedFallbackIfHeap(mLocation, mMallocSizeOf);
}
size_t Result() const { return mSum; }

View File

@ -366,33 +366,69 @@ VectorImage::FrameRect(uint32_t aWhichFrame)
}
size_t
VectorImage::SizeOfSourceWithComputedFallback(MallocSizeOf aMallocSizeOf) const
VectorImage::HeapSizeOfSourceWithComputedFallback(MallocSizeOf aMallocSizeOf) const
{
nsIDocument* doc = mSVGDocumentWrapper->GetDocument();
if (!doc) {
return 0; // No document, so no memory used for the document.
}
nsWindowSizes windowSizes(aMallocSizeOf);
doc->DocAddSizeOfIncludingThis(&windowSizes);
if (windowSizes.getTotalSize() == 0) {
// MallocSizeOf fails on this platform. Because we also use this method for
// determining the size of cache entries, we need to return something
// reasonable here. Unfortunately, there's no way to estimate the document's
// size accurately, so we just use a constant value of 100KB, which will
// generally underestimate the true size.
return 100 * 1024;
}
return windowSizes.getTotalSize();
// 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::SizeOfDecoded(gfxMemoryLocation aLocation,
MallocSizeOf aMallocSizeOf) const
VectorImage::HeapSizeOfDecodedWithComputedFallback(MallocSizeOf aMallocSizeOf) const
{
return SurfaceCache::SizeOfSurfaces(ImageKey(this), aLocation, aMallocSizeOf);
// 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}/...")
// XXX(seth): Same goes for the other *SizeOfDecoded() methods. We'll do this
// in bug 921300 or one of its blockers. For now it seems worthwhile to get
// this memory accounted for, even if it gets listed under 'raster'. It does
// make some perverse sense, since we are after all reporting on raster data
// here - it just happens to be computed from a vector document.
return SurfaceCache::SizeOfSurfaces(ImageKey(this),
gfxMemoryLocation::IN_PROCESS_HEAP,
aMallocSizeOf);
}
size_t
VectorImage::NonHeapSizeOfDecoded() const
{
return SurfaceCache::SizeOfSurfaces(ImageKey(this),
gfxMemoryLocation::IN_PROCESS_NONHEAP,
nullptr);
}
size_t
VectorImage::OutOfProcessSizeOfDecoded() const
{
return SurfaceCache::SizeOfSurfaces(ImageKey(this),
gfxMemoryLocation::OUT_OF_PROCESS,
nullptr);
}
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->DocAddSizeOfIncludingThis(&windowSizes);
return windowSizes.getTotalSize();
}
nsresult

View File

@ -42,9 +42,12 @@ public:
uint32_t aFlags);
virtual nsIntRect FrameRect(uint32_t aWhichFrame) MOZ_OVERRIDE;
virtual size_t SizeOfSourceWithComputedFallback(MallocSizeOf aMallocSizeOf) const MOZ_OVERRIDE;
virtual size_t SizeOfDecoded(gfxMemoryLocation aLocation,
MallocSizeOf aMallocSizeOf) const MOZ_OVERRIDE;
virtual size_t HeapSizeOfSourceWithComputedFallback(MallocSizeOf aMallocSizeOf) const;
virtual size_t HeapSizeOfDecodedWithComputedFallback(MallocSizeOf aMallocSizeOf) const;
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,

View File

@ -905,9 +905,11 @@ void imgFrame::SetCompositingFailed(bool val)
mCompositingFailed = val;
}
// If |aLocation| indicates this is heap memory, we try to measure things with
// |aMallocSizeOf|. If that fails (because the platform doesn't support it) or
// it's non-heap memory, we fall back to computing the size analytically.
size_t
imgFrame::SizeOfExcludingThis(gfxMemoryLocation aLocation,
MallocSizeOf aMallocSizeOf) const
imgFrame::SizeOfExcludingThisWithComputedFallbackIfHeap(gfxMemoryLocation aLocation, MallocSizeOf aMallocSizeOf) const
{
// aMallocSizeOf is only used if aLocation==gfxMemoryLocation::IN_PROCESS_HEAP. It
// should be nullptr otherwise.
@ -919,8 +921,13 @@ imgFrame::SizeOfExcludingThis(gfxMemoryLocation aLocation,
size_t n = 0;
if (mPalettedImageData && aLocation == gfxMemoryLocation::IN_PROCESS_HEAP) {
n += aMallocSizeOf(mPalettedImageData);
size_t n2 = aMallocSizeOf(mPalettedImageData);
if (n2 == 0) {
n2 = GetImageDataLength() + PaletteDataLength();
}
n += n2;
}
if (mImageSurface && aLocation == gfxMemoryLocation::IN_PROCESS_HEAP) {
n += aMallocSizeOf(mImageSurface);
}

View File

@ -131,8 +131,9 @@ public:
TemporaryRef<SourceSurface> CachedSurface();
size_t SizeOfExcludingThis(gfxMemoryLocation aLocation,
MallocSizeOf aMallocSizeOf) const;
size_t SizeOfExcludingThisWithComputedFallbackIfHeap(
gfxMemoryLocation aLocation,
MallocSizeOf aMallocSizeOf) const;
uint8_t GetPaletteDepth() const { return mPaletteDepth; }
uint32_t PaletteDataLength() const {

View File

@ -54,39 +54,75 @@ MOZ_DEFINE_MALLOC_SIZE_OF(ImagesMallocSizeOf)
class imgMemoryReporter MOZ_FINAL : public nsIMemoryReporter
{
~imgMemoryReporter() { }
~imgMemoryReporter() {}
public:
NS_DECL_ISUPPORTS
NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport,
nsISupports* aData, bool aAnonymize)
NS_IMETHOD CollectReports(nsIMemoryReporterCallback *aHandleReport,
nsISupports *aData, bool aAnonymize)
{
nsresult rv;
nsTArray<ImageMemoryCounter> chrome;
nsTArray<ImageMemoryCounter> content;
nsTArray<ImageMemoryCounter> uncached;
ImageSizes chrome;
ImageSizes content;
ImageSizes uncached;
for (uint32_t i = 0; i < mKnownLoaders.Length(); i++) {
mKnownLoaders[i]->mChromeCache.EnumerateRead(DoRecordCounter, &chrome);
mKnownLoaders[i]->mCache.EnumerateRead(DoRecordCounter, &content);
mKnownLoaders[i]->mChromeCache.EnumerateRead(EntryImageSizes, &chrome);
mKnownLoaders[i]->mCache.EnumerateRead(EntryImageSizes, &content);
MutexAutoLock lock(mKnownLoaders[i]->mUncachedImagesMutex);
mKnownLoaders[i]->
mUncachedImages.EnumerateEntries(DoRecordCounterUncached, &uncached);
mKnownLoaders[i]->mUncachedImages.EnumerateEntries(EntryUncachedImageSizes, &uncached);
}
// Note that we only need to anonymize content image URIs.
rv = ReportCounterArray(aHandleReport, aData, chrome, "images/chrome");
rv = ReportInfoArray(aHandleReport, aData, chrome.mRasterUsedImageInfo,
"images/chrome/raster/used");
NS_ENSURE_SUCCESS(rv, rv);
rv = ReportCounterArray(aHandleReport, aData, content,
"images/content", aAnonymize);
rv = ReportInfoArray(aHandleReport, aData, chrome.mRasterUnusedImageInfo,
"images/chrome/raster/unused");
NS_ENSURE_SUCCESS(rv, rv);
// Uncached images may be content or chrome, so anonymize them.
rv = ReportCounterArray(aHandleReport, aData, uncached,
"images/uncached", aAnonymize);
rv = ReportInfoArray(aHandleReport, aData, chrome.mVectorUsedImageDocInfo,
"images/chrome/vector/used/documents");
NS_ENSURE_SUCCESS(rv, rv);
rv = ReportInfoArray(aHandleReport, aData, chrome.mVectorUnusedImageDocInfo,
"images/chrome/vector/unused/documents");
NS_ENSURE_SUCCESS(rv, rv);
rv = ReportInfoArray(aHandleReport, aData, content.mRasterUsedImageInfo,
"images/content/raster/used", aAnonymize);
NS_ENSURE_SUCCESS(rv, rv);
rv = ReportInfoArray(aHandleReport, aData, content.mRasterUnusedImageInfo,
"images/content/raster/unused", aAnonymize);
NS_ENSURE_SUCCESS(rv, rv);
rv = ReportInfoArray(aHandleReport, aData, content.mVectorUsedImageDocInfo,
"images/content/vector/used/documents", aAnonymize);
NS_ENSURE_SUCCESS(rv, rv);
rv = ReportInfoArray(aHandleReport, aData, content.mVectorUnusedImageDocInfo,
"images/content/vector/unused/documents", aAnonymize);
NS_ENSURE_SUCCESS(rv, rv);
// The uncached images can contain both content and chrome images, so anonymize it.
rv = ReportInfoArray(aHandleReport, aData, uncached.mRasterUsedImageInfo,
"images/uncached/raster/used", aAnonymize);
NS_ENSURE_SUCCESS(rv, rv);
rv = ReportInfoArray(aHandleReport, aData, uncached.mRasterUnusedImageInfo,
"images/uncached/raster/unused", aAnonymize);
NS_ENSURE_SUCCESS(rv, rv);
rv = ReportInfoArray(aHandleReport, aData, uncached.mVectorUsedImageDocInfo,
"images/uncached/vector/used/documents", aAnonymize);
NS_ENSURE_SUCCESS(rv, rv);
rv = ReportInfoArray(aHandleReport, aData, uncached.mVectorUnusedImageDocInfo,
"images/uncached/vector/unused/documents", aAnonymize);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
@ -96,8 +132,7 @@ public:
{
size_t n = 0;
for (uint32_t i = 0; i < imgLoader::sMemReporter->mKnownLoaders.Length(); i++) {
imgLoader::sMemReporter->mKnownLoaders[i]->
mCache.EnumerateRead(DoRecordCounterUsedDecoded, &n);
imgLoader::sMemReporter->mKnownLoaders[i]->mCache.EnumerateRead(EntryUsedUncompressedSize, &n);
}
return n;
}
@ -115,343 +150,306 @@ public:
private:
nsTArray<imgLoader*> mKnownLoaders;
struct MemoryCounter
struct RasterSizes
{
MemoryCounter()
: mSource(0)
, mDecodedHeap(0)
, mDecodedNonHeap(0)
{ }
size_t mRaw;
size_t mUncompressedHeap;
size_t mUncompressedNonheap;
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; }
RasterSizes()
: mRaw(0)
, mUncompressedHeap(0)
, mUncompressedNonheap(0)
{}
MemoryCounter& operator+=(const MemoryCounter& aOther)
void add(const RasterSizes &aOther)
{
mSource += aOther.mSource;
mDecodedHeap += aOther.mDecodedHeap;
mDecodedNonHeap += aOther.mDecodedNonHeap;
return *this;
mRaw += aOther.mRaw;
mUncompressedHeap += aOther.mUncompressedHeap;
mUncompressedNonheap += aOther.mUncompressedNonheap;
}
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
bool isNotable() const
{
const size_t NotableThreshold = 16 * 1024;
size_t total = mValues.Source() + mValues.DecodedHeap()
+ mValues.DecodedNonHeap();
size_t total = mRaw + mUncompressedHeap + mUncompressedNonheap;
return total >= NotableThreshold;
}
private:
nsCString mURI;
uint16_t mType;
MemoryCounter mValues;
bool mIsUsed;
};
struct MemoryTotal
struct VectorDocSizes
{
MemoryTotal& operator+=(const ImageMemoryCounter& aImageCounter)
{
if (aImageCounter.Type() == imgIContainer::TYPE_RASTER) {
if (aImageCounter.IsUsed()) {
mUsedRasterCounter += aImageCounter.Values();
} else {
mUnusedRasterCounter += aImageCounter.Values();
}
} else if (aImageCounter.Type() == imgIContainer::TYPE_VECTOR) {
if (aImageCounter.IsUsed()) {
mUsedVectorCounter += aImageCounter.Values();
} else {
mUnusedVectorCounter += aImageCounter.Values();
}
} else {
MOZ_CRASH("Unexpected image type");
}
size_t mSize;
return *this;
VectorDocSizes()
: mSize(0)
{}
void add(const VectorDocSizes &aOther)
{
mSize += aOther.mSize;
}
const MemoryCounter& UsedRaster() const { return mUsedRasterCounter; }
const MemoryCounter& UnusedRaster() const { return mUnusedRasterCounter; }
const MemoryCounter& UsedVector() const { return mUsedVectorCounter; }
const MemoryCounter& UnusedVector() const { return mUnusedVectorCounter; }
private:
MemoryCounter mUsedRasterCounter;
MemoryCounter mUnusedRasterCounter;
MemoryCounter mUsedVectorCounter;
MemoryCounter mUnusedVectorCounter;
bool isNotable() const
{
const size_t NotableThreshold = 16 * 1024;
size_t total = mSize;
return total >= NotableThreshold;
}
};
template <typename ImageSizes>
struct ImageInfo
{
ImageSizes mSizes;
nsCString mURI;
};
// Reports all images of a single kind, e.g. all used chrome images.
nsresult ReportCounterArray(nsIHandleReportCallback* aHandleReport,
nsISupports* aData,
const nsTArray<ImageMemoryCounter>& aCounterArray,
const char* aPathPrefix,
bool aAnonymize = false)
struct ImageSizes
{
nsTArray<ImageInfo<RasterSizes> > mRasterUsedImageInfo;
nsTArray<ImageInfo<RasterSizes> > mRasterUnusedImageInfo;
nsTArray<ImageInfo<VectorDocSizes> > mVectorUsedImageDocInfo;
nsTArray<ImageInfo<VectorDocSizes> > mVectorUnusedImageDocInfo;
};
// Definitions specialized for raster and vector images are below.
template<typename Sizes>
nsresult ReportSizes(nsIMemoryReporterCallback *aHandleReport,
nsISupports *aData,
const nsACString &aPathPrefix,
const nsACString &aLocation,
Sizes aSizes);
// This is used to report all images of a single kind, e.g. all
// "chrome/raster/used" images.
template <typename Sizes>
nsresult ReportInfoArray(nsIMemoryReporterCallback *aHandleReport,
nsISupports *aData,
const nsTArray<ImageInfo<Sizes> > &aInfoArray,
const char *aPathPartStr, bool aAnonymize = false)
{
nsresult rv;
MemoryTotal summaryTotal;
MemoryTotal nonNotableTotal;
Sizes totalSizes;
Sizes nonNotableSizes;
nsCString pathPart(aPathPartStr);
nsCString explicitPathPrefix(aPathPartStr);
explicitPathPrefix.Insert("explicit/", 0);
// Report notable images, and compute total and non-notable aggregate sizes.
for (uint32_t i = 0; i < aCounterArray.Length(); i++) {
ImageMemoryCounter counter = aCounterArray[i];
for (uint32_t i = 0; i < aInfoArray.Length(); i++) {
ImageInfo<Sizes> info = aInfoArray[i];
if (aAnonymize) {
counter.URI().Truncate();
counter.URI().AppendPrintf("<anonymized-%u>", i);
info.mURI.Truncate();
info.mURI.AppendPrintf("<anonymized-%u>", i);
} else {
// The URI could be an extremely long data: URI. Truncate if needed.
// info.mURI can be a data: URI, and thus extremely long. Truncate if
// necessary.
static const size_t max = 256;
if (counter.URI().Length() > max) {
counter.URI().Truncate(max);
counter.URI().AppendLiteral(" (truncated)");
if (info.mURI.Length() > max) {
info.mURI.Truncate(max);
info.mURI.AppendLiteral(" (truncated)");
}
counter.URI().ReplaceChar('/', '\\');
info.mURI.ReplaceChar('/', '\\');
}
summaryTotal += counter;
totalSizes.add(info.mSizes);
if (counter.IsNotable()) {
rv = ReportCounter(aHandleReport, aData, aPathPrefix, counter);
NS_ENSURE_SUCCESS(rv, rv);
if (!info.mSizes.isNotable()) {
nonNotableSizes.add(info.mSizes);
} else {
nonNotableTotal += counter;
// Report the notable image.
rv = ReportSizes(aHandleReport, aData, explicitPathPrefix,
info.mURI, info.mSizes);
NS_ENSURE_SUCCESS(rv, rv);
}
}
// Report non-notable images in aggregate.
rv = ReportTotal(aHandleReport, aData, /* aExplicit = */ true,
aPathPrefix, "<non-notable images>/", nonNotableTotal);
rv = ReportSizes(aHandleReport, aData, explicitPathPrefix,
NS_LITERAL_CSTRING("<non-notable images>"),
nonNotableSizes);
NS_ENSURE_SUCCESS(rv, rv);
// Report a summary in aggregate, outside of the explicit tree.
rv = ReportTotal(aHandleReport, aData, /* aExplicit = */ false,
aPathPrefix, "", summaryTotal);
// Report image totals in aggregate, without the "explicit/" prefix.
rv = ReportSizes(aHandleReport, aData, pathPart, EmptyCString(),
totalSizes);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
static nsresult ReportCounter(nsIHandleReportCallback* aHandleReport,
nsISupports* aData,
const char* aPathPrefix,
const ImageMemoryCounter& aCounter)
{
nsAutoCString pathPrefix(NS_LITERAL_CSTRING("explicit/"));
pathPrefix.Append(aPathPrefix);
pathPrefix.Append(aCounter.Type() == imgIContainer::TYPE_RASTER
? "/raster/"
: "/vector/");
pathPrefix.Append(aCounter.IsUsed() ? "used/" : "unused/");
pathPrefix.Append("image(");
if (aCounter.URI().IsEmpty()) {
pathPrefix.Append("<unknown URI>");
} else {
pathPrefix.Append(aCounter.URI());
}
pathPrefix.Append(")/");
return ReportValues(aHandleReport, aData, pathPrefix, aCounter.Values());
}
static nsresult ReportTotal(nsIHandleReportCallback* aHandleReport,
nsISupports* aData,
bool aExplicit,
const char* aPathPrefix,
const char* aPathInfix,
const MemoryTotal& aTotal)
{
nsresult rv;
nsAutoCString pathPrefix;
if (aExplicit) {
pathPrefix.Append("explicit/");
}
pathPrefix.Append(aPathPrefix);
nsAutoCString rasterUsedPrefix(pathPrefix);
rasterUsedPrefix.Append("/raster/used/");
rasterUsedPrefix.Append(aPathInfix);
rv = ReportValues(aHandleReport, aData, rasterUsedPrefix,
aTotal.UsedRaster());
NS_ENSURE_SUCCESS(rv, rv);
nsAutoCString rasterUnusedPrefix(pathPrefix);
rasterUnusedPrefix.Append("/raster/unused/");
rasterUnusedPrefix.Append(aPathInfix);
rv = ReportValues(aHandleReport, aData, rasterUnusedPrefix,
aTotal.UnusedRaster());
NS_ENSURE_SUCCESS(rv, rv);
nsAutoCString vectorUsedPrefix(pathPrefix);
vectorUsedPrefix.Append("/vector/used/");
vectorUsedPrefix.Append(aPathInfix);
rv = ReportValues(aHandleReport, aData, vectorUsedPrefix,
aTotal.UsedVector());
NS_ENSURE_SUCCESS(rv, rv);
nsAutoCString vectorUnusedPrefix(pathPrefix);
vectorUnusedPrefix.Append("/vector/unused/");
vectorUnusedPrefix.Append(aPathInfix);
rv = ReportValues(aHandleReport, aData, vectorUnusedPrefix,
aTotal.UnusedVector());
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
static nsresult ReportValues(nsIHandleReportCallback* aHandleReport,
nsISupports* aData,
const nsACString& aPathPrefix,
const MemoryCounter& aCounter)
{
nsresult rv;
rv = ReportValue(aHandleReport, aData, KIND_HEAP, aPathPrefix,
"source",
"Raster image source data and vector image documents.",
aCounter.Source());
NS_ENSURE_SUCCESS(rv, rv);
rv = ReportValue(aHandleReport, aData, KIND_HEAP, aPathPrefix,
"decoded-heap",
"Decoded image data which is stored on the heap.",
aCounter.DecodedHeap());
NS_ENSURE_SUCCESS(rv, rv);
rv = ReportValue(aHandleReport, aData, KIND_NONHEAP, aPathPrefix,
"decoded-nonheap",
"Decoded image data which isn't stored on the heap.",
aCounter.DecodedNonHeap());
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
static nsresult ReportValue(nsIHandleReportCallback* aHandleReport,
nsISupports* aData,
int32_t aKind,
const nsACString& aPathPrefix,
const char* aPathSuffix,
const char* aDescription,
size_t aValue)
{
if (aValue == 0) {
return NS_OK;
}
nsAutoCString desc(aDescription);
nsAutoCString path(aPathPrefix);
path.Append(aPathSuffix);
return aHandleReport->Callback(EmptyCString(), path, aKind, UNITS_BYTES,
aValue, desc, aData);
}
static PLDHashOperator DoRecordCounter(const nsACString&,
imgCacheEntry* aEntry,
void* aUserArg)
static PLDHashOperator EntryImageSizes(const nsACString&,
imgCacheEntry *aEntry,
void *aUserArg)
{
nsRefPtr<imgRequest> req = aEntry->GetRequest();
RecordCounterForRequest(req,
static_cast<nsTArray<ImageMemoryCounter>*>(aUserArg),
!aEntry->HasNoProxies());
Image *image = static_cast<Image*>(req->mImage.get());
if (image) {
ImageSizes *sizes = static_cast<ImageSizes*>(aUserArg);
nsRefPtr<ImageURL> imageURL(image->GetURI());
nsAutoCString spec;
imageURL->GetSpec(spec);
ImageInfo<RasterSizes> rasterInfo;
rasterInfo.mSizes.mRaw =
image->HeapSizeOfSourceWithComputedFallback(ImagesMallocSizeOf);
rasterInfo.mSizes.mUncompressedHeap =
image->HeapSizeOfDecodedWithComputedFallback(ImagesMallocSizeOf);
rasterInfo.mSizes.mUncompressedNonheap = image->NonHeapSizeOfDecoded();
rasterInfo.mURI = spec.get();
if (!aEntry->HasNoProxies()) {
sizes->mRasterUsedImageInfo.AppendElement(rasterInfo);
} else {
sizes->mRasterUnusedImageInfo.AppendElement(rasterInfo);
}
ImageInfo<VectorDocSizes> vectorInfo;
vectorInfo.mSizes.mSize =
image->HeapSizeOfVectorImageDocument(&vectorInfo.mURI);
if (!vectorInfo.mURI.IsEmpty()) {
if (!aEntry->HasNoProxies()) {
sizes->mVectorUsedImageDocInfo.AppendElement(vectorInfo);
} else {
sizes->mVectorUnusedImageDocInfo.AppendElement(vectorInfo);
}
}
}
return PL_DHASH_NEXT;
}
static PLDHashOperator DoRecordCounterUncached(nsPtrHashKey<imgRequest>* aEntry,
static PLDHashOperator EntryUncachedImageSizes(nsPtrHashKey<imgRequest>* aEntry,
void* aUserArg)
{
nsRefPtr<imgRequest> req = aEntry->GetKey();
RecordCounterForRequest(req,
static_cast<nsTArray<ImageMemoryCounter>*>(aUserArg),
req->HasConsumers());
Image *image = static_cast<Image*>(req->mImage.get());
if (image) {
ImageSizes *sizes = static_cast<ImageSizes*>(aUserArg);
nsRefPtr<ImageURL> imageURL(image->GetURI());
nsAutoCString spec;
imageURL->GetSpec(spec);
ImageInfo<RasterSizes> rasterInfo;
rasterInfo.mSizes.mRaw =
image->HeapSizeOfSourceWithComputedFallback(ImagesMallocSizeOf);
rasterInfo.mSizes.mUncompressedHeap =
image->HeapSizeOfDecodedWithComputedFallback(ImagesMallocSizeOf);
rasterInfo.mSizes.mUncompressedNonheap = image->NonHeapSizeOfDecoded();
rasterInfo.mURI = spec.get();
if (req->HasConsumers()) {
sizes->mRasterUsedImageInfo.AppendElement(rasterInfo);
} else {
sizes->mRasterUnusedImageInfo.AppendElement(rasterInfo);
}
ImageInfo<VectorDocSizes> vectorInfo;
vectorInfo.mSizes.mSize =
image->HeapSizeOfVectorImageDocument(&vectorInfo.mURI);
if (!vectorInfo.mURI.IsEmpty()) {
if (req->HasConsumers()) {
sizes->mVectorUsedImageDocInfo.AppendElement(vectorInfo);
} else {
sizes->mVectorUnusedImageDocInfo.AppendElement(vectorInfo);
}
}
}
return PL_DHASH_NEXT;
}
static void RecordCounterForRequest(imgRequest* aRequest,
nsTArray<ImageMemoryCounter>* aArray,
bool aIsUsed)
static PLDHashOperator EntryUsedUncompressedSize(const nsACString&,
imgCacheEntry *aEntry,
void *aUserArg)
{
auto image = static_cast<Image*>(aRequest->mImage.get());
if (!image) {
return;
if (!aEntry->HasNoProxies()) {
size_t *n = static_cast<size_t*>(aUserArg);
nsRefPtr<imgRequest> req = aEntry->GetRequest();
Image *image = static_cast<Image*>(req->mImage.get());
if (image) {
// Both this and EntryImageSizes measure
// images/content/raster/used/uncompressed 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.
*n += image->HeapSizeOfDecodedWithComputedFallback(moz_malloc_size_of);
*n += image->NonHeapSizeOfDecoded();
}
}
nsRefPtr<ImageURL> imageURL(image->GetURI());
nsAutoCString spec;
imageURL->GetSpec(spec);
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);
}
static PLDHashOperator DoRecordCounterUsedDecoded(const nsACString&,
imgCacheEntry* aEntry,
void* aUserArg)
{
if (aEntry->HasNoProxies()) {
return PL_DHASH_NEXT;
}
nsRefPtr<imgRequest> req = aEntry->GetRequest();
auto image = static_cast<Image*>(req->mImage.get());
if (!image) {
return PL_DHASH_NEXT;
}
// Both this and EntryImageSizes measure images/content/raster/used/decoded
// 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.
auto n = static_cast<size_t*>(aUserArg);
*n += image->SizeOfDecoded(gfxMemoryLocation::IN_PROCESS_HEAP,
moz_malloc_size_of);
*n += image->SizeOfDecoded(gfxMemoryLocation::IN_PROCESS_NONHEAP,
moz_malloc_size_of);
return PL_DHASH_NEXT;
}
};
// Specialisation of this method for raster images.
template<>
nsresult imgMemoryReporter::ReportSizes(
nsIMemoryReporterCallback *aHandleReport, nsISupports *aData,
const nsACString &aPathPrefix, const nsACString &aLocation,
RasterSizes aSizes)
{
#define REPORT(_pathPrefix, _pathSuffix, _location, _kind, _amount, _desc) \
do { \
if (_amount > 0) { \
nsCString path(_pathPrefix); \
path.Append("/"); \
if (!_location.IsEmpty()) { \
path.Append("image("); \
path.Append(_location); \
path.Append(")/"); \
} \
path.Append(_pathSuffix); \
nsresult rv; \
rv = aHandleReport->Callback(EmptyCString(), path, _kind, UNITS_BYTES, \
_amount, NS_LITERAL_CSTRING(_desc), aData);\
NS_ENSURE_SUCCESS(rv, rv); \
} \
} while (0)
REPORT(aPathPrefix, "raw", aLocation, KIND_HEAP,
aSizes.mRaw, "Compressed image data.");
REPORT(aPathPrefix, "uncompressed-heap", aLocation, KIND_HEAP,
aSizes.mUncompressedHeap, "Uncompressed image data.");
REPORT(aPathPrefix, "uncompressed-nonheap", aLocation, KIND_NONHEAP,
aSizes.mUncompressedNonheap, "Uncompressed image data.");
#undef REPORT
return NS_OK;
}
// Specialisation of this method for vector images.
template<>
nsresult imgMemoryReporter::ReportSizes(
nsIMemoryReporterCallback *aHandleReport, nsISupports *aData,
const nsACString &aPathPrefix, const nsACString &aLocation,
VectorDocSizes aSizes)
{
#define REPORT(_pathPrefix, _location, _amount, _desc) \
do { \
if (_amount > 0) { \
nsCString path(_pathPrefix); \
if (!_location.IsEmpty()) { \
path.Append("/document("); \
path.Append(_location); \
path.Append(")"); \
} \
nsresult rv; \
rv = aHandleReport->Callback(EmptyCString(), path, KIND_HEAP, \
UNITS_BYTES, _amount, \
NS_LITERAL_CSTRING(_desc), aData); \
NS_ENSURE_SUCCESS(rv, rv); \
} \
} while (0)
REPORT(aPathPrefix, aLocation, aSizes.mSize,
"Parsed vector image documents.");
#undef REPORT
return NS_OK;
}
NS_IMPL_ISUPPORTS(imgMemoryReporter, nsIMemoryReporter)
NS_IMPL_ISUPPORTS(nsProgressNotificationProxy,

View File

@ -455,10 +455,8 @@ void imgRequest::SetIsInCache(bool incache)
void imgRequest::UpdateCacheEntrySize()
{
if (mCacheEntry) {
size_t size = mImage->SizeOfSourceWithComputedFallback(moz_malloc_size_of);
mCacheEntry->SetDataSize(size);
}
if (mCacheEntry)
mCacheEntry->SetDataSize(mImage->SizeOfData());
}
void imgRequest::SetCacheValidation(imgCacheEntry* aCacheEntry, nsIRequest* aRequest)

View File

@ -141,6 +141,9 @@ public:
// Resize the cache entry to 0 if it exists
void ResetCacheEntry();
// Update the cache entry size based on the image container
void UpdateCacheEntrySize();
// OK to use on any thread.
nsresult GetURI(ImageURL **aURI);
nsresult GetCurrentURI(nsIURI **aURI);
@ -180,9 +183,6 @@ private:
// Returns whether we've got a reference to the cache entry.
bool HasCacheEntry() const;
// Update the cache entry size based on the image container.
void UpdateCacheEntrySize();
// Return the priority of the underlying network request, or return
// PRIORITY_NORMAL if it doesn't support nsISupportsPriority.
int32_t Priority() const;

View File

@ -776,6 +776,12 @@ void imgRequestProxy::OnDecodeComplete()
nsCOMPtr<imgINotificationObserver> kungFuDeathGrip(mListener);
mListener->Notify(this, imgINotificationObserver::DECODE_COMPLETE, nullptr);
}
if (GetOwner()) {
// We finished the decode, and thus have the decoded frames. Update the cache
// entry size to take this into account.
GetOwner()->UpdateCacheEntrySize();
}
}
void imgRequestProxy::OnDiscard()
@ -787,6 +793,10 @@ void imgRequestProxy::OnDiscard()
nsCOMPtr<imgINotificationObserver> kungFuDeathGrip(mListener);
mListener->Notify(this, imgINotificationObserver::DISCARD, nullptr);
}
if (GetOwner()) {
// Update the cache entry size, since we just got rid of frame data.
GetOwner()->UpdateCacheEntrySize();
}
}
void imgRequestProxy::OnUnlockedDraw()