Bug 1059654. Report memory for all images, not just those that are in the image cache. r=seth f=njn

The image cache is just a map from URI to imgRequest, so if two images have the same URI (because we couldn't re-use the cached one for whatever reason (ie expired))  one won't be in the cache.

Also images that have no proxies will eventually get removed from the cache, if they are kept alive we still want to report them.
This commit is contained in:
Timothy Nikkel 2014-09-05 16:36:11 -05:00
parent ea0e14d0a1
commit aa2ff91951
4 changed files with 140 additions and 11 deletions

View File

@ -63,10 +63,13 @@ public:
nsresult rv;
ImageSizes chrome;
ImageSizes content;
ImageSizes uncached;
for (uint32_t i = 0; i < mKnownLoaders.Length(); i++) {
mKnownLoaders[i]->mChromeCache.EnumerateRead(EntryImageSizes, &chrome);
mKnownLoaders[i]->mCache.EnumerateRead(EntryImageSizes, &content);
MutexAutoLock lock(mKnownLoaders[i]->mUncachedImagesMutex);
mKnownLoaders[i]->mUncachedImages.EnumerateEntries(EntryUncachedImageSizes, &uncached);
}
// Note that we only need to anonymize content image URIs.
@ -103,6 +106,23 @@ public:
"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;
}
@ -299,6 +319,45 @@ private:
return PL_DHASH_NEXT;
}
static PLDHashOperator EntryUncachedImageSizes(nsPtrHashKey<imgRequest>* aEntry,
void* aUserArg)
{
nsRefPtr<imgRequest> req = aEntry->GetKey();
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 PLDHashOperator EntryUsedUncompressedSize(const nsACString&,
imgCacheEntry *aEntry,
void *aUserArg)
@ -481,6 +540,7 @@ static void NewRequestAndEntry(bool aForcePrincipalCheckForCacheEntry, imgLoader
{
nsRefPtr<imgRequest> request = new imgRequest(aLoader);
nsRefPtr<imgCacheEntry> entry = new imgCacheEntry(aLoader, request, aForcePrincipalCheckForCacheEntry);
aLoader->AddToUncachedImages(request);
request.forget(aRequest);
entry.forget(aEntry);
}
@ -935,7 +995,7 @@ imgLoader::PBSingleton()
}
imgLoader::imgLoader()
: mRespectPrivacy(false)
: mUncachedImagesMutex("imgLoader::UncachedImages"), mRespectPrivacy(false)
{
sMemReporter->AddRef();
sMemReporter->RegisterLoader(this);
@ -955,10 +1015,25 @@ imgLoader::GetInstance()
return loader.forget();
}
static PLDHashOperator ClearLoaderPointer(nsPtrHashKey<imgRequest>* aEntry,
void *aUserArg)
{
nsRefPtr<imgRequest> req = aEntry->GetKey();
req->ClearLoader();
return PL_DHASH_NEXT;
}
imgLoader::~imgLoader()
{
ClearChromeImageCache();
ClearImageCache();
{
// If there are any of our imgRequest's left they are in the uncached
// images set, so clear their pointer to us.
MutexAutoLock lock(mUncachedImagesMutex);
mUncachedImages.EnumerateEntries(ClearLoaderPointer, nullptr);
}
sMemReporter->UnregisterLoader(this);
sMemReporter->Release();
}
@ -1239,6 +1314,7 @@ bool imgLoader::PutIntoCache(nsIURI *key, imgCacheEntry *entry)
nsRefPtr<imgRequest> request = entry->GetRequest();
request->SetIsInCache(true);
RemoveFromUncachedImages(request);
return true;
}
@ -1635,6 +1711,7 @@ bool imgLoader::RemoveFromCache(nsCString& spec,
nsRefPtr<imgRequest> request = entry->GetRequest();
request->SetIsInCache(false);
AddToUncachedImages(request);
return true;
}
@ -1668,6 +1745,7 @@ bool imgLoader::RemoveFromCache(imgCacheEntry *entry)
entry->SetEvicted(true);
request->SetIsInCache(false);
AddToUncachedImages(request);
return true;
}
@ -1721,6 +1799,19 @@ nsresult imgLoader::EvictEntries(imgCacheQueue &aQueueToClear)
return NS_OK;
}
void imgLoader::AddToUncachedImages(imgRequest* aRequest)
{
MutexAutoLock lock(mUncachedImagesMutex);
mUncachedImages.PutEntry(aRequest);
}
void imgLoader::RemoveFromUncachedImages(imgRequest* aRequest)
{
MutexAutoLock lock(mUncachedImagesMutex);
mUncachedImages.RemoveEntry(aRequest);
}
#define LOAD_FLAGS_CACHE_MASK (nsIRequest::LOAD_BYPASS_CACHE | \
nsIRequest::LOAD_FROM_CACHE)

View File

@ -8,6 +8,7 @@
#define imgLoader_h__
#include "mozilla/Attributes.h"
#include "mozilla/Mutex.h"
#include "imgILoader.h"
#include "imgICache.h"
@ -170,11 +171,11 @@ private: // data
#include <vector>
#define NS_IMGLOADER_CID \
{ /* 9f6a0d2e-1dd1-11b2-a5b8-951f13c846f7 */ \
0x9f6a0d2e, \
0x1dd1, \
0x11b2, \
{0xa5, 0xb8, 0x95, 0x1f, 0x13, 0xc8, 0x46, 0xf7} \
{ /* c1354898-e3fe-4602-88a7-c4520c21cb4e */ \
0xc1354898, \
0xe3fe, \
0x4602, \
{0x88, 0xa7, 0xc4, 0x52, 0x0c, 0x21, 0xcb, 0x4e} \
}
class imgCacheQueue
@ -216,6 +217,8 @@ class imgLoader MOZ_FINAL : public imgILoader,
public:
typedef mozilla::image::ImageURL ImageURL;
typedef nsRefPtrHashtable<nsCStringHashKey, imgCacheEntry> imgCacheTable;
typedef nsTHashtable<nsPtrHashKey<imgRequest>> imgSet;
typedef mozilla::Mutex Mutex;
NS_DECL_ISUPPORTS
NS_DECL_IMGILOADER
@ -286,6 +289,9 @@ public:
bool PutIntoCache(nsIURI *key, imgCacheEntry *entry);
void AddToUncachedImages(imgRequest* aRequest);
void RemoveFromUncachedImages(imgRequest* aRequest);
// Returns true if we should prefer evicting cache entry |two| over cache
// entry |one|.
// This mixes units in the worst way, but provides reasonable results.
@ -375,6 +381,16 @@ private: // data
imgCacheTable mChromeCache;
imgCacheQueue mChromeCacheQueue;
// Hash set of every imgRequest for this loader that isn't in mCache or
// mChromeCache. The union over all imgLoader's of mCache, mChromeCache, and
// mUncachedImages should be every imgRequest that is alive. These are weak
// pointers so we rely on the imgRequest destructor to remove itself.
imgSet mUncachedImages;
// The imgRequest can have refs to them held on non-main thread, so we need
// a mutex because we modify the uncached images set from the imgRequest
// destructor.
Mutex mUncachedImagesMutex;
static double sCacheTimeWeight;
static uint32_t sCacheMaxSize;
static imgMemoryReporter* sMemReporter;

View File

@ -73,6 +73,9 @@ imgRequest::imgRequest(imgLoader* aLoader)
imgRequest::~imgRequest()
{
if (mLoader) {
mLoader->RemoveFromUncachedImages(this);
}
if (mURI) {
nsAutoCString spec;
mURI->GetSpec(spec);
@ -126,6 +129,10 @@ nsresult imgRequest::Init(nsIURI *aURI,
return NS_OK;
}
void imgRequest::ClearLoader() {
mLoader = nullptr;
}
already_AddRefed<imgStatusTracker>
imgRequest::GetStatusTracker()
{
@ -169,7 +176,9 @@ void imgRequest::AddProxy(imgRequestProxy *proxy)
nsRefPtr<imgStatusTracker> statusTracker = GetStatusTracker();
if (statusTracker->ConsumerCount() == 0) {
NS_ABORT_IF_FALSE(mURI, "Trying to SetHasProxies without key uri.");
mLoader->SetHasProxies(mURI);
if (mLoader) {
mLoader->SetHasProxies(mURI);
}
}
statusTracker->AddConsumer(proxy);
@ -199,7 +208,9 @@ nsresult imgRequest::RemoveProxy(imgRequestProxy *proxy, nsresult aStatus)
if (mCacheEntry) {
NS_ABORT_IF_FALSE(mURI, "Removing last observer without key uri.");
mLoader->SetHasNoProxies(mURI, mCacheEntry);
if (mLoader) {
mLoader->SetHasNoProxies(mURI, mCacheEntry);
}
}
#if defined(PR_LOGGING)
else {
@ -375,17 +386,24 @@ void imgRequest::RemoveFromCache()
{
LOG_SCOPE(GetImgLog(), "imgRequest::RemoveFromCache");
if (mIsInCache) {
if (mIsInCache && mLoader) {
// mCacheEntry is nulled out when we have no more observers.
if (mCacheEntry)
if (mCacheEntry) {
mLoader->RemoveFromCache(mCacheEntry);
else
} else {
mLoader->RemoveFromCache(mURI);
}
}
mCacheEntry = nullptr;
}
bool imgRequest::HasConsumers()
{
nsRefPtr<imgStatusTracker> statusTracker = GetStatusTracker();
return statusTracker && statusTracker->ConsumerCount() > 0;
}
int32_t imgRequest::Priority() const
{
int32_t priority = nsISupportsPriority::PRIORITY_NORMAL;

View File

@ -63,6 +63,8 @@ public:
nsIPrincipal* aLoadingPrincipal,
int32_t aCORSMode);
void ClearLoader();
// Callers must call imgRequestProxy::Notify later.
void AddProxy(imgRequestProxy *proxy);
@ -190,6 +192,8 @@ private:
bool IsBlockingOnload() const;
void SetBlockingOnload(bool block) const;
bool HasConsumers();
public:
NS_DECL_NSISTREAMLISTENER
NS_DECL_NSITHREADRETARGETABLESTREAMLISTENER