Bug 1610381 - Part 2. Improve image memory reporting with more state information. r=jrmuizel

This patch adds error and progress tracker states to the memory dump. It
also now will include requests that have yet to create an image, and
fills in what information it is able to without it (such as URI, error
and progress tracker states).

Additionally the notability of an image has changed. If there are any
errors, missing progress trackers, or incomplete surfaces, they will
also now be notable. This is a departure from just the memory footprint.

Differential Revision: https://phabricator.services.mozilla.com/D60495

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Andrew Osmond 2020-01-21 14:39:59 +00:00
Родитель 3fabc043bf
Коммит 3fb86e5d59
4 изменённых файлов: 100 добавлений и 13 удалений

Просмотреть файл

@ -5,6 +5,7 @@
#include "Image.h"
#include "imgRequest.h"
#include "Layers.h" // for LayerManager
#include "nsRefreshDriver.h"
#include "nsContentUtils.h"
@ -20,9 +21,36 @@ namespace image {
// Memory Reporting
///////////////////////////////////////////////////////////////////////////////
ImageMemoryCounter::ImageMemoryCounter(imgRequest* aRequest,
SizeOfState& aState, bool aIsUsed)
: mProgress(UINT32_MAX),
mType(UINT16_MAX),
mIsUsed(aIsUsed),
mHasError(false) {
MOZ_ASSERT(aRequest);
// We don't have the image object yet, but we can get some information.
nsCOMPtr<nsIURI> imageURL;
nsresult rv = aRequest->GetURI(getter_AddRefs(imageURL));
if (NS_SUCCEEDED(rv) && imageURL) {
imageURL->GetSpec(mURI);
}
mType = imgIContainer::TYPE_REQUEST;
mHasError = NS_FAILED(aRequest->GetImageErrorCode());
RefPtr<ProgressTracker> tracker = aRequest->GetProgressTracker();
if (tracker) {
mProgress = tracker->GetProgress();
}
}
ImageMemoryCounter::ImageMemoryCounter(Image* aImage, SizeOfState& aState,
bool aIsUsed)
: mIsUsed(aIsUsed) {
: mProgress(UINT32_MAX),
mType(UINT16_MAX),
mIsUsed(aIsUsed),
mHasError(false) {
MOZ_ASSERT(aImage);
// Extract metadata about the image.
@ -38,6 +66,12 @@ ImageMemoryCounter::ImageMemoryCounter(Image* aImage, SizeOfState& aState,
mIntrinsicSize.SizeTo(width, height);
mType = aImage->GetType();
mHasError = aImage->HasError();
RefPtr<ProgressTracker> tracker = aImage->GetProgressTracker();
if (tracker) {
mProgress = tracker->GetProgress();
}
// Populate memory counters for source and decoded data.
mValues.SetSource(aImage->SizeOfSourceWithComputedFallback(aState));

Просмотреть файл

@ -18,6 +18,7 @@
#include "ProgressTracker.h"
#include "SurfaceCache.h"
class imgRequest;
class nsIRequest;
class nsIInputStream;
@ -103,6 +104,7 @@ struct SurfaceMemoryCounter {
};
struct ImageMemoryCounter {
ImageMemoryCounter(imgRequest* aRequest, SizeOfState& aState, bool aIsUsed);
ImageMemoryCounter(Image* aImage, SizeOfState& aState, bool aIsUsed);
nsCString& URI() { return mURI; }
@ -110,14 +112,35 @@ struct ImageMemoryCounter {
const nsTArray<SurfaceMemoryCounter>& Surfaces() const { return mSurfaces; }
const gfx::IntSize IntrinsicSize() const { return mIntrinsicSize; }
const MemoryCounter& Values() const { return mValues; }
uint32_t Progress() const { return mProgress; }
uint16_t Type() const { return mType; }
bool IsUsed() const { return mIsUsed; }
bool HasError() const { return mHasError; }
bool IsNotable() const {
// Errors or requests without images are always notable.
if (mHasError || mProgress == UINT32_MAX || mProgress & FLAG_HAS_ERROR ||
mType == imgIContainer::TYPE_REQUEST) {
return true;
}
// Sufficiently large images are notable.
const size_t NotableThreshold = 16 * 1024;
size_t total =
mValues.Source() + mValues.DecodedHeap() + mValues.DecodedNonHeap();
return total >= NotableThreshold;
if (total >= NotableThreshold) {
return true;
}
// Incomplete images are always notable as well; the odds of capturing
// mid-decode should be fairly low.
for (const auto& surface : mSurfaces) {
if (!surface.IsFinished()) {
return true;
}
}
return false;
}
private:
@ -125,8 +148,10 @@ struct ImageMemoryCounter {
nsTArray<SurfaceMemoryCounter> mSurfaces;
gfx::IntSize mIntrinsicSize;
MemoryCounter mValues;
uint32_t mProgress;
uint16_t mType;
const bool mIsUsed;
bool mHasError;
};
///////////////////////////////////////////////////////////////////////////////

Просмотреть файл

@ -131,6 +131,7 @@ interface imgIContainer : nsISupports
*/
const unsigned short TYPE_RASTER = 0;
const unsigned short TYPE_VECTOR = 1;
const unsigned short TYPE_REQUEST = 2;
/**
* The type of this image (one of the TYPE_* values above).

Просмотреть файл

@ -213,6 +213,8 @@ class imgMemoryReporter final : public nsIMemoryReporter {
} else {
mUnusedVectorCounter += aImageCounter.Values();
}
} else if (aImageCounter.Type() == imgIContainer::TYPE_REQUEST) {
// Nothing to do, we did not get to the point of having an image.
} else {
MOZ_CRASH("Unexpected image type");
}
@ -284,10 +286,33 @@ class imgMemoryReporter final : public nsIMemoryReporter {
layers::SharedSurfacesMemoryReport& aSharedSurfaces) {
nsAutoCString pathPrefix(NS_LITERAL_CSTRING("explicit/"));
pathPrefix.Append(aPathPrefix);
pathPrefix.Append(aCounter.Type() == imgIContainer::TYPE_RASTER
? "/raster/"
: "/vector/");
switch (aCounter.Type()) {
case imgIContainer::TYPE_RASTER:
pathPrefix.AppendLiteral("/raster/");
break;
case imgIContainer::TYPE_VECTOR:
pathPrefix.AppendLiteral("/vector/");
break;
case imgIContainer::TYPE_REQUEST:
pathPrefix.AppendLiteral("/request/");
break;
default:
pathPrefix.AppendLiteral("/unknown=");
pathPrefix.AppendInt(aCounter.Type());
pathPrefix.AppendLiteral("/");
break;
}
pathPrefix.Append(aCounter.IsUsed() ? "used/" : "unused/");
if (aCounter.HasError()) {
pathPrefix.AppendLiteral("err/");
}
pathPrefix.AppendLiteral("progress=");
pathPrefix.AppendInt(aCounter.Progress(), 16);
pathPrefix.AppendLiteral("/");
pathPrefix.AppendLiteral("image(");
pathPrefix.AppendInt(aCounter.IntrinsicSize().width);
pathPrefix.AppendLiteral("x");
@ -491,15 +516,17 @@ class imgMemoryReporter final : public nsIMemoryReporter {
static void RecordCounterForRequest(imgRequest* aRequest,
nsTArray<ImageMemoryCounter>* aArray,
bool aIsUsed) {
RefPtr<image::Image> image = aRequest->GetImage();
if (!image) {
return;
}
SizeOfState state(ImagesMallocSizeOf);
ImageMemoryCounter counter(image, state, aIsUsed);
aArray->AppendElement(std::move(counter));
RefPtr<image::Image> image = aRequest->GetImage();
if (image) {
ImageMemoryCounter counter(image, state, aIsUsed);
aArray->AppendElement(std::move(counter));
} else {
// We can at least record some information about the image from the
// request, and mark it as not knowing the image type yet.
ImageMemoryCounter counter(aRequest, state, aIsUsed);
aArray->AppendElement(std::move(counter));
}
}
};