Bug 923302 - Add explicit memory reporting for SurfaceCache. r=njn

--HG--
extra : rebase_source : 08187da628ee01f41a2722913ddd0461c446808c
This commit is contained in:
Seth Fowler 2014-10-01 17:16:42 -07:00
parent e9226a8d8c
commit 1c2757be11
4 changed files with 125 additions and 40 deletions

View File

@ -1010,10 +1010,13 @@ size_t
RasterImage::SizeOfDecodedWithComputedFallbackIfHeap(gfxMemoryLocation aLocation,
MallocSizeOf aMallocSizeOf) const
{
return mFrameBlender
? mFrameBlender->SizeOfDecodedWithComputedFallbackIfHeap(aLocation,
aMallocSizeOf)
: 0;
size_t n = 0;
n += SurfaceCache::SizeOfSurfaces(ImageKey(this), aLocation, aMallocSizeOf);
if (mFrameBlender) {
n += mFrameBlender->SizeOfDecodedWithComputedFallbackIfHeap(aLocation,
aMallocSizeOf);
}
return n;
}
size_t

View File

@ -54,7 +54,7 @@ static StaticRefPtr<SurfaceCacheImpl> sInstance;
// SurfaceCache Implementation
///////////////////////////////////////////////////////////////////////////////
/*
/**
* Cost models the cost of storing a surface in the cache. Right now, this is
* simply an estimate of the size of the surface in bytes, but in the future it
* may be worth taking into account the cost of rematerializing the surface as
@ -67,7 +67,7 @@ static Cost ComputeCost(const IntSize& aSize)
return aSize.width * aSize.height * 4; // width * height * 4 bytes (32bpp)
}
/*
/**
* Since we want to be able to make eviction decisions based on cost, we need to
* be able to look up the CachedSurface which has a certain cost as well as the
* cost associated with a certain CachedSurface. To make this possible, in data
@ -108,7 +108,7 @@ private:
Cost mCost;
};
/*
/**
* A CachedSurface associates a surface with a key that uniquely identifies that
* surface.
*/
@ -158,6 +158,34 @@ public:
nsExpirationState* GetExpirationState() { return &mExpirationState; }
Lifetime GetLifetime() const { return mLifetime; }
// A helper type used by SurfaceCacheImpl::SizeOfSurfacesSum.
struct SizeOfSurfacesSum
{
SizeOfSurfacesSum(gfxMemoryLocation aLocation,
MallocSizeOf aMallocSizeOf)
: mLocation(aLocation)
, mMallocSizeOf(aMallocSizeOf)
, mSum(0)
{ }
void Add(CachedSurface* aCachedSurface)
{
if (!aCachedSurface || !aCachedSurface->mSurface) {
return;
}
mSum += aCachedSurface->mSurface->
SizeOfExcludingThisWithComputedFallbackIfHeap(mLocation, mMallocSizeOf);
}
size_t Result() const { return mSum; }
private:
gfxMemoryLocation mLocation;
MallocSizeOf mMallocSizeOf;
size_t mSum;
};
private:
nsExpirationState mExpirationState;
nsRefPtr<imgFrame> mSurface;
@ -522,38 +550,53 @@ public:
NS_IMETHOD
CollectReports(nsIHandleReportCallback* aHandleReport,
nsISupports* aData,
bool aAnonymize)
bool aAnonymize) MOZ_OVERRIDE
{
// We have explicit memory reporting for the surface cache which is more
// accurate than the cost metrics we report here, but these metrics are
// still useful to report, since they control the cache's behavior.
nsresult rv;
rv = MOZ_COLLECT_REPORT("imagelib-surface-cache-total",
rv = MOZ_COLLECT_REPORT("imagelib-surface-cache-estimated-total",
KIND_OTHER, UNITS_BYTES,
SizeOfSurfacesEstimate(),
"Total memory used by the imagelib surface cache.");
(mMaxCost - mAvailableCost),
"Estimated total memory used by the imagelib "
"surface cache.");
NS_ENSURE_SUCCESS(rv, rv);
rv = MOZ_COLLECT_REPORT("imagelib-surface-cache-locked",
rv = MOZ_COLLECT_REPORT("imagelib-surface-cache-estimated-locked",
KIND_OTHER, UNITS_BYTES,
SizeOfLockedSurfacesEstimate(),
"Memory used by locked surfaces in the imagelib "
"surface cache.");
mLockedCost,
"Estimated memory used by locked surfaces in the "
"imagelib surface cache.");
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
// XXX(seth): This is currently only an estimate and, since we don't know
// which surfaces are in GPU memory and which aren't, it's reported as
// KIND_OTHER and will also show up in heap-unclassified. Bug 923302 will
// make this nicer.
Cost SizeOfSurfacesEstimate() const
size_t SizeOfSurfaces(const ImageKey aImageKey,
gfxMemoryLocation aLocation,
MallocSizeOf aMallocSizeOf)
{
return mMaxCost - mAvailableCost;
nsRefPtr<ImageSurfaceCache> cache = GetImageCache(aImageKey);
if (!cache) {
return 0; // No surfaces for this image.
}
Cost SizeOfLockedSurfacesEstimate() const
// Sum the size of all surfaces in the per-image cache.
CachedSurface::SizeOfSurfacesSum sum(aLocation, aMallocSizeOf);
cache->ForEach(DoSizeOfSurfacesSum, &sum);
return sum.Result();
}
static PLDHashOperator DoSizeOfSurfacesSum(const SurfaceKey&,
CachedSurface* aSurface,
void* aSum)
{
return mLockedCost;
auto sum = static_cast<CachedSurface::SizeOfSurfacesSum*>(aSum);
sum->Add(aSurface);
return PL_DHASH_NEXT;
}
private:
@ -597,7 +640,9 @@ private:
{
NS_DECL_ISUPPORTS
NS_IMETHOD Observe(nsISupports*, const char* aTopic, const char16_t*)
NS_IMETHOD Observe(nsISupports*,
const char* aTopic,
const char16_t*) MOZ_OVERRIDE
{
if (sInstance && strcmp(aTopic, "memory-pressure") == 0) {
sInstance->DiscardAll();
@ -756,5 +801,18 @@ SurfaceCache::DiscardAll()
}
}
/* static */ size_t
SurfaceCache::SizeOfSurfaces(const ImageKey aImageKey,
gfxMemoryLocation aLocation,
MallocSizeOf aMallocSizeOf)
{
MOZ_ASSERT(NS_IsMainThread());
if (!sInstance) {
return 0;
}
return sInstance->SizeOfSurfaces(aImageKey, aLocation, aMallocSizeOf);
}
} // namespace image
} // namespace mozilla

View File

@ -12,7 +12,9 @@
#define MOZILLA_IMAGELIB_SURFACECACHE_H_
#include "mozilla/Maybe.h" // for Maybe
#include "mozilla/MemoryReporting.h" // for MallocSizeOf
#include "mozilla/HashFunctions.h" // for HashGeneric and AddToHash
#include "gfx2DGlue.h" // for gfxMemoryLocation
#include "gfxPoint.h" // for gfxSize
#include "nsCOMPtr.h" // for already_AddRefed
#include "mozilla/gfx/Point.h" // for mozilla::gfx::IntSize
@ -293,6 +295,23 @@ struct SurfaceCache
*/
static void DiscardAll();
/**
* Computes the size of the surfaces stored for the given image at the given
* memory location.
*
* 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.
*/
static size_t SizeOfSurfaces(const ImageKey aImageKey,
gfxMemoryLocation aLocation,
MallocSizeOf aMallocSizeOf);
private:
virtual ~SurfaceCache() = 0; // Forbid instantiation.
};

View File

@ -384,25 +384,30 @@ VectorImage::HeapSizeOfDecodedWithComputedFallback(MallocSizeOf aMallocSizeOf) c
// 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;
// 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
{
// 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;
return SurfaceCache::SizeOfSurfaces(ImageKey(this),
gfxMemoryLocation::IN_PROCESS_NONHEAP,
nullptr);
}
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;
return SurfaceCache::SizeOfSurfaces(ImageKey(this),
gfxMemoryLocation::OUT_OF_PROCESS,
nullptr);
}
MOZ_DEFINE_MALLOC_SIZE_OF(WindowsMallocSizeOf);