bug 688125 - part 2 - add memory reporting for fonts in the gfxFontCache. r=njn

This commit is contained in:
Jonathan Kew 2012-03-23 12:14:16 +00:00
parent c278b0a18f
commit 5ffe5203cf
10 changed files with 260 additions and 12 deletions

View File

@ -762,3 +762,20 @@ gfxDWriteFont::MeasureGlyphWidth(PRUint16 aGlyph)
}
return 0;
}
void
gfxDWriteFont::SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf,
FontCacheSizes* aSizes) const
{
gfxFont::SizeOfExcludingThis(aMallocSizeOf, aSizes);
aSizes->mFontInstances += aMallocSizeOf(mMetrics) +
mGlyphWidths.SizeOfExcludingThis(nsnull, aMallocSizeOf);
}
void
gfxDWriteFont::SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf,
FontCacheSizes* aSizes) const
{
aSizes->mFontInstances += aMallocSizeOf(this);
SizeOfExcludingThis(aMallocSizeOf, aSizes);
}

View File

@ -92,6 +92,11 @@ public:
virtual mozilla::TemporaryRef<mozilla::gfx::GlyphRenderingOptions> GetGlyphRenderingOptions();
virtual void SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf,
FontCacheSizes* aSizes) const;
virtual void SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf,
FontCacheSizes* aSizes) const;
protected:
friend class gfxDWriteShaper;

View File

@ -661,3 +661,20 @@ gfxFT2Font::FillGlyphDataForChar(PRUint32 ch, CachedGlyphData *gd)
gd->rsbDelta = face->glyph->rsb_delta;
gd->xAdvance = face->glyph->advance.x;
}
void
gfxFT2Font::SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf,
FontCacheSizes* aSizes) const
{
gfxFont::SizeOfExcludingThis(aMallocSizeOf, aSizes);
aSizes->mFontInstances +=
mCharGlyphCache.SizeOfExcludingThis(nsnull, aMallocSizeOf);
}
void
gfxFT2Font::SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf,
FontCacheSizes* aSizes) const
{
aSizes->mFontInstances += aMallocSizeOf(this);
SizeOfExcludingThis(aMallocSizeOf, aSizes);
}

View File

@ -96,6 +96,11 @@ public: // new functions
return &entry->mData;
}
virtual void SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf,
FontCacheSizes* aSizes) const;
virtual void SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf,
FontCacheSizes* aSizes) const;
protected:
virtual bool ShapeWord(gfxContext *aContext,
gfxShapedWord *aShapedWord,

View File

@ -47,7 +47,6 @@
#include "nsReadableUtils.h"
#include "nsExpirationTracker.h"
#include "nsILanguageAtomService.h"
#include "nsIMemoryReporter.h"
#include "nsITimer.h"
#include "gfxFont.h"
@ -1048,6 +1047,52 @@ gfxFontFamily::SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf,
* shaped-word caches to free up memory.
*/
NS_IMPL_ISUPPORTS1(gfxFontCache::MemoryReporter, nsIMemoryMultiReporter)
NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN(FontCacheMallocSizeOf, "font-cache")
NS_IMETHODIMP
gfxFontCache::MemoryReporter::GetName(nsACString &aName)
{
aName.AssignLiteral("font-cache");
return NS_OK;
}
NS_IMETHODIMP
gfxFontCache::MemoryReporter::CollectReports
(nsIMemoryMultiReporterCallback* aCb,
nsISupports* aClosure)
{
FontCacheSizes sizes;
gfxFontCache::GetCache()->SizeOfIncludingThis(&FontCacheMallocSizeOf,
&sizes);
aCb->Callback(EmptyCString(),
NS_LITERAL_CSTRING("explicit/gfx/font-cache"),
nsIMemoryReporter::KIND_HEAP, nsIMemoryReporter::UNITS_BYTES,
sizes.mFontInstances,
NS_LITERAL_CSTRING("Memory used for active font instances."),
aClosure);
aCb->Callback(EmptyCString(),
NS_LITERAL_CSTRING("explicit/gfx/font-shaped-words"),
nsIMemoryReporter::KIND_HEAP, nsIMemoryReporter::UNITS_BYTES,
sizes.mShapedWords,
NS_LITERAL_CSTRING("Memory used to cache shaped glyph data."),
aClosure);
return NS_OK;
}
NS_IMETHODIMP
gfxFontCache::MemoryReporter::GetExplicitNonHeap(PRInt64* aAmount)
{
// This reporter only measures heap memory.
*aAmount = 0;
return NS_OK;
}
// Observer for the memory-pressure notification, to trigger
// flushing of the shaped-word caches
class MemoryPressureObserver : public nsIObserver,
@ -1079,7 +1124,11 @@ gfxFontCache::Init()
{
NS_ASSERTION(!gGlobalCache, "Where did this come from?");
gGlobalCache = new gfxFontCache();
return gGlobalCache ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
if (!gGlobalCache) {
return NS_ERROR_OUT_OF_MEMORY;
}
NS_RegisterMemoryMultiReporter(new MemoryReporter);
return NS_OK;
}
void
@ -1240,6 +1289,39 @@ gfxFontCache::ClearCachedWordsForFont(HashEntry* aHashEntry, void* aUserData)
return PL_DHASH_NEXT;
}
/*static*/
size_t
gfxFontCache::SizeOfFontEntryExcludingThis(HashEntry* aHashEntry,
nsMallocSizeOfFun aMallocSizeOf,
void* aUserArg)
{
HashEntry *entry = static_cast<HashEntry*>(aHashEntry);
FontCacheSizes *sizes = static_cast<FontCacheSizes*>(aUserArg);
entry->mFont->SizeOfExcludingThis(aMallocSizeOf, sizes);
// The font records its size in the |sizes| parameter, so we return zero
// here to the hashtable enumerator.
return 0;
}
void
gfxFontCache::SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf,
FontCacheSizes* aSizes) const
{
// TODO: add the overhead of the expiration tracker (generation arrays)
mFonts.SizeOfExcludingThis(SizeOfFontEntryExcludingThis,
aMallocSizeOf, aSizes);
}
void
gfxFontCache::SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf,
FontCacheSizes* aSizes) const
{
aSizes->mFontInstances += aMallocSizeOf(this);
SizeOfExcludingThis(aMallocSizeOf, aSizes);
}
void
gfxFont::RunMetrics::CombineWith(const RunMetrics& aOther, bool aOtherIsOnLeft)
{
@ -2589,10 +2671,40 @@ gfxFont::SynthesizeSpaceWidth(PRUint32 aCh)
}
}
/*static*/ size_t
gfxFont::WordCacheEntrySizeOfExcludingThis(CacheHashEntry* aHashEntry,
nsMallocSizeOfFun aMallocSizeOf,
void* aUserArg)
{
return aMallocSizeOf(aHashEntry->mShapedWord.get());
}
void
gfxFont::SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf,
FontCacheSizes* aSizes) const
{
for (PRUint32 i = 0; i < mGlyphExtentsArray.Length(); ++i) {
aSizes->mFontInstances +=
mGlyphExtentsArray[i]->SizeOfIncludingThis(aMallocSizeOf);
}
aSizes->mShapedWords +=
mWordCache.SizeOfExcludingThis(WordCacheEntrySizeOfExcludingThis,
aMallocSizeOf);
}
void
gfxFont::SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf,
FontCacheSizes* aSizes) const
{
aSizes->mFontInstances += aMallocSizeOf(this);
SizeOfExcludingThis(aMallocSizeOf, aSizes);
}
gfxGlyphExtents::~gfxGlyphExtents()
{
#ifdef DEBUG_TEXT_RUN_STORAGE_METRICS
gGlyphExtentsWidthsTotalSize += mContainedGlyphWidths.ComputeSize();
gGlyphExtentsWidthsTotalSize +=
mContainedGlyphWidths.SizeOfExcludingThis(&FontCacheMallocSizeOf);
gGlyphExtentsCount++;
#endif
MOZ_COUNT_DTOR(gfxGlyphExtents);
@ -2636,21 +2748,19 @@ gfxGlyphExtents::GlyphWidths::~GlyphWidths()
}
}
#ifdef DEBUG
PRUint32
gfxGlyphExtents::GlyphWidths::ComputeSize()
gfxGlyphExtents::GlyphWidths::SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf) const
{
PRUint32 i;
PRUint32 size = mBlocks.Capacity()*sizeof(PtrBits);
PRUint32 size = mBlocks.SizeOfExcludingThis(aMallocSizeOf);
for (i = 0; i < mBlocks.Length(); ++i) {
PtrBits bits = mBlocks[i];
if (bits && !(bits & 0x1)) {
size += BLOCK_SIZE*sizeof(PRUint16);
size += aMallocSizeOf(reinterpret_cast<void*>(bits));
}
}
return size;
}
#endif
void
gfxGlyphExtents::GlyphWidths::Set(PRUint32 aGlyphID, PRUint16 aWidth)
@ -2702,6 +2812,19 @@ gfxGlyphExtents::SetTightGlyphExtents(PRUint32 aGlyphID, const gfxRect& aExtents
entry->height = aExtentsAppUnits.Height();
}
size_t
gfxGlyphExtents::SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf) const
{
return mContainedGlyphWidths.SizeOfExcludingThis(aMallocSizeOf) +
mTightGlyphExtents.SizeOfExcludingThis(nsnull, aMallocSizeOf);
}
size_t
gfxGlyphExtents::SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const
{
return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
}
gfxFontGroup::gfxFontGroup(const nsAString& aFamilies, const gfxFontStyle *aStyle, gfxUserFontSet *aUserFontSet)
: mFamilies(aFamilies), mStyle(*aStyle), mUnderlineOffset(UNDERLINE_OFFSET_NOT_SET)
{

View File

@ -59,6 +59,7 @@
#include "nsISupportsImpl.h"
#include "gfxPattern.h"
#include "mozilla/HashFunctions.h"
#include "nsIMemoryReporter.h"
typedef struct _cairo_scaled_font cairo_scaled_font_t;
@ -742,6 +743,15 @@ struct gfxTextRange {
* completely, with all its words, and avoid the cost of aging the words
* individually. That only happens with longer-lived fonts.
*/
struct FontCacheSizes {
FontCacheSizes()
: mFontInstances(0), mShapedWords(0)
{ }
size_t mFontInstances; // memory used by instances of gfxFont subclasses
size_t mShapedWords; // memory used by the per-font shapedWord caches
};
class THEBES_API gfxFontCache MOZ_FINAL : public nsExpirationTracker<gfxFont,3> {
public:
enum {
@ -795,7 +805,20 @@ public:
mFonts.EnumerateEntries(ClearCachedWordsForFont, nsnull);
}
void SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf,
FontCacheSizes* aSizes) const;
void SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf,
FontCacheSizes* aSizes) const;
protected:
class MemoryReporter
: public nsIMemoryMultiReporter
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIMEMORYMULTIREPORTER
};
void DestroyFont(gfxFont *aFont);
static gfxFontCache *gGlobalCache;
@ -828,6 +851,10 @@ protected:
gfxFont* mFont;
};
static size_t SizeOfFontEntryExcludingThis(HashEntry* aHashEntry,
nsMallocSizeOfFun aMallocSizeOf,
void* aUserArg);
nsTHashtable<HashEntry> mFonts;
static PLDHashOperator ClearCachedWordsForFont(HashEntry* aHashEntry, void*);
@ -999,6 +1026,9 @@ public:
PRUint32 GetAppUnitsPerDevUnit() { return mAppUnitsPerDevUnit; }
size_t SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf) const;
size_t SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const;
private:
class HashEntry : public nsUint32HashKey {
public:
@ -1035,9 +1065,7 @@ private:
return widths[indexInBlock];
}
#ifdef DEBUG
PRUint32 ComputeSize();
#endif
PRUint32 SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf) const;
~GlyphWidths();
@ -1056,7 +1084,7 @@ private:
nsTArray<PtrBits> mBlocks;
};
GlyphWidths mContainedGlyphWidths;
nsTHashtable<HashEntry> mTightGlyphExtents;
PRUint32 mAppUnitsPerDevUnit;
@ -1493,6 +1521,11 @@ public:
}
}
virtual void SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf,
FontCacheSizes* aSizes) const;
virtual void SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf,
FontCacheSizes* aSizes) const;
protected:
// Call the appropriate shaper to generate glyphs for aText and store
// them into aShapedWord.
@ -1577,6 +1610,11 @@ protected:
nsAutoPtr<gfxShapedWord> mShapedWord;
};
static size_t
WordCacheEntrySizeOfExcludingThis(CacheHashEntry* aHashEntry,
nsMallocSizeOfFun aMallocSizeOf,
void* aUserArg);
nsTHashtable<CacheHashEntry> mWordCache;
static PLDHashOperator AgeCacheEntry(CacheHashEntry *aEntry, void *aUserData);

View File

@ -560,3 +560,20 @@ gfxGDIFont::GetGlyphWidth(gfxContext *aCtx, PRUint16 aGID)
return -1;
}
void
gfxGDIFont::SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf,
FontCacheSizes* aSizes) const
{
gfxFont::SizeOfExcludingThis(aMallocSizeOf, aSizes);
aSizes->mFontInstances += aMallocSizeOf(mMetrics) +
mGlyphWidths.SizeOfExcludingThis(nsnull, aMallocSizeOf);
}
void
gfxGDIFont::SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf,
FontCacheSizes* aSizes) const
{
aSizes->mFontInstances += aMallocSizeOf(this);
SizeOfExcludingThis(aMallocSizeOf, aSizes);
}

View File

@ -88,6 +88,11 @@ public:
// get hinted glyph width in pixels as 16.16 fixed-point value
virtual PRInt32 GetGlyphWidth(gfxContext *aCtx, PRUint16 aGID);
virtual void SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf,
FontCacheSizes* aSizes) const;
virtual void SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf,
FontCacheSizes* aSizes) const;
protected:
virtual void CreatePlatformShaper();

View File

@ -509,3 +509,19 @@ gfxMacFont::GetScaledFont()
return mAzureFont;
}
void
gfxMacFont::SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf,
FontCacheSizes* aSizes) const
{
gfxFont::SizeOfExcludingThis(aMallocSizeOf, aSizes);
// mCGFont is shared with the font entry, so not counted here;
// and we don't have APIs to measure the cairo mFontFace object
}
void
gfxMacFont::SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf,
FontCacheSizes* aSizes) const
{
aSizes->mFontInstances += aMallocSizeOf(this);
SizeOfExcludingThis(aMallocSizeOf, aSizes);
}

View File

@ -81,6 +81,11 @@ public:
mozilla::RefPtr<mozilla::gfx::ScaledFont> GetScaledFont();
virtual void SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf,
FontCacheSizes* aSizes) const;
virtual void SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf,
FontCacheSizes* aSizes) const;
protected:
virtual void CreatePlatformShaper();