combine glyph and image bulk alloc, and adjust initial alloc size, to reduce total waste from 50% to 30%

add diagnostics to measure cache efficiency

BUG=

Review URL: https://codereview.chromium.org/17449012

git-svn-id: http://skia.googlecode.com/svn/trunk@9691 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
reed@google.com 2013-06-19 19:25:36 +00:00
parent 3832da1e9c
commit 6757a3c71f
5 changed files with 44 additions and 11 deletions

View File

@ -42,6 +42,7 @@ public:
size_t unalloc(void* ptr); size_t unalloc(void* ptr);
size_t totalCapacity() const { return fTotalCapacity; } size_t totalCapacity() const { return fTotalCapacity; }
size_t totalUsed() const { return fTotalUsed; }
int blockCount() const { return fBlockCount; } int blockCount() const { return fBlockCount; }
/** /**
@ -58,6 +59,7 @@ private:
size_t fMinSize; size_t fMinSize;
size_t fChunkSize; size_t fChunkSize;
size_t fTotalCapacity; size_t fTotalCapacity;
size_t fTotalUsed; // will be <= fTotalCapacity
int fBlockCount; int fBlockCount;
Block* newBlock(size_t bytes, AllocFailType ftype); Block* newBlock(size_t bytes, AllocFailType ftype);

View File

@ -52,6 +52,7 @@ SkChunkAlloc::SkChunkAlloc(size_t minSize) {
fMinSize = minSize; fMinSize = minSize;
fChunkSize = fMinSize; fChunkSize = fMinSize;
fTotalCapacity = 0; fTotalCapacity = 0;
fTotalUsed = 0;
fBlockCount = 0; fBlockCount = 0;
} }
@ -64,6 +65,7 @@ void SkChunkAlloc::reset() {
fBlock = NULL; fBlock = NULL;
fChunkSize = fMinSize; // reset to our initial minSize fChunkSize = fMinSize; // reset to our initial minSize
fTotalCapacity = 0; fTotalCapacity = 0;
fTotalUsed = 0;
fBlockCount = 0; fBlockCount = 0;
} }
@ -90,6 +92,8 @@ SkChunkAlloc::Block* SkChunkAlloc::newBlock(size_t bytes, AllocFailType ftype) {
} }
void* SkChunkAlloc::alloc(size_t bytes, AllocFailType ftype) { void* SkChunkAlloc::alloc(size_t bytes, AllocFailType ftype) {
fTotalUsed += bytes;
bytes = SkAlign4(bytes); bytes = SkAlign4(bytes);
Block* block = fBlock; Block* block = fBlock;

View File

@ -48,14 +48,13 @@ bool gSkSuppressFontCachePurgeSpew;
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
#define kMinGlphAlloc (sizeof(SkGlyph) * 64) // so we don't grow our arrays a lot
#define kMinImageAlloc (24 * 64) // should be pointsize-dependent #define kMinGlyphCount 16
#define kMinGlyphImageSize (16*2)
#define METRICS_RESERVE_COUNT 128 // so we don't grow this array a lot #define kMinAllocAmount ((sizeof(SkGlyph) + kMinGlyphImageSize) * kMinGlyphCount)
SkGlyphCache::SkGlyphCache(SkTypeface* typeface, const SkDescriptor* desc) SkGlyphCache::SkGlyphCache(SkTypeface* typeface, const SkDescriptor* desc)
: fGlyphAlloc(kMinGlphAlloc) : fGlyphAlloc(kMinAllocAmount) {
, fImageAlloc(kMinImageAlloc) {
SkASSERT(typeface); SkASSERT(typeface);
fPrev = fNext = NULL; fPrev = fNext = NULL;
@ -69,9 +68,9 @@ SkGlyphCache::SkGlyphCache(SkTypeface* typeface, const SkDescriptor* desc)
// init with 0xFF so that the charCode field will be -1, which is invalid // init with 0xFF so that the charCode field will be -1, which is invalid
memset(fCharToGlyphHash, 0xFF, sizeof(fCharToGlyphHash)); memset(fCharToGlyphHash, 0xFF, sizeof(fCharToGlyphHash));
fMemoryUsed = sizeof(*this) + kMinGlphAlloc + kMinImageAlloc; fMemoryUsed = sizeof(*this);
fGlyphArray.setReserve(METRICS_RESERVE_COUNT); fGlyphArray.setReserve(kMinGlyphCount);
fMetricsCount = 0; fMetricsCount = 0;
fAdvanceCount = 0; fAdvanceCount = 0;
@ -79,6 +78,30 @@ SkGlyphCache::SkGlyphCache(SkTypeface* typeface, const SkDescriptor* desc)
} }
SkGlyphCache::~SkGlyphCache() { SkGlyphCache::~SkGlyphCache() {
#if 0
{
size_t ptrMem = fGlyphArray.count() * sizeof(SkGlyph*);
size_t glyphAlloc = fGlyphAlloc.totalCapacity();
size_t glyphHashUsed = 0;
size_t uniHashUsed = 0;
for (int i = 0; i < kHashCount; ++i) {
glyphHashUsed += fGlyphHash[i] ? sizeof(fGlyphHash[0]) : 0;
uniHashUsed += fCharToGlyphHash[i].fID != 0xFFFFFFFF ? sizeof(fCharToGlyphHash[0]) : 0;
}
size_t glyphUsed = fGlyphArray.count() * sizeof(SkGlyph);
size_t imageUsed = 0;
for (int i = 0; i < fGlyphArray.count(); ++i) {
const SkGlyph& g = *fGlyphArray[i];
if (g.fImage) {
imageUsed += g.fHeight * g.rowBytes();
}
}
printf("glyphPtrArray,%zu, Alloc,%zu, imageUsed,%zu, glyphUsed,%zu, glyphHashAlloc,%zu, glyphHashUsed,%zu, unicharHashAlloc,%zu, unicharHashUsed,%zu\n",
ptrMem, glyphAlloc, imageUsed, glyphUsed, sizeof(fGlyphHash), glyphHashUsed, sizeof(fCharToGlyphHash), uniHashUsed);
}
#endif
SkGlyph** gptr = fGlyphArray.begin(); SkGlyph** gptr = fGlyphArray.begin();
SkGlyph** stop = fGlyphArray.end(); SkGlyph** stop = fGlyphArray.end();
while (gptr < stop) { while (gptr < stop) {
@ -296,7 +319,7 @@ const void* SkGlyphCache::findImage(const SkGlyph& glyph) {
if (glyph.fWidth > 0 && glyph.fWidth < kMaxGlyphWidth) { if (glyph.fWidth > 0 && glyph.fWidth < kMaxGlyphWidth) {
if (glyph.fImage == NULL) { if (glyph.fImage == NULL) {
size_t size = glyph.computeImageSize(); size_t size = glyph.computeImageSize();
const_cast<SkGlyph&>(glyph).fImage = fImageAlloc.alloc(size, const_cast<SkGlyph&>(glyph).fImage = fGlyphAlloc.alloc(size,
SkChunkAlloc::kReturnNil_AllocFailType); SkChunkAlloc::kReturnNil_AllocFailType);
// check that alloc() actually succeeded // check that alloc() actually succeeded
if (glyph.fImage) { if (glyph.fImage) {
@ -708,7 +731,7 @@ void SkGlyphCache::validate() const {
SkASSERT(glyph); SkASSERT(glyph);
SkASSERT(fGlyphAlloc.contains(glyph)); SkASSERT(fGlyphAlloc.contains(glyph));
if (glyph->fImage) { if (glyph->fImage) {
SkASSERT(fImageAlloc.contains(glyph->fImage)); SkASSERT(fGlyphAlloc.contains(glyph->fImage));
} }
} }
#endif #endif

View File

@ -230,7 +230,6 @@ private:
SkGlyph* fGlyphHash[kHashCount]; SkGlyph* fGlyphHash[kHashCount];
SkTDArray<SkGlyph*> fGlyphArray; SkTDArray<SkGlyph*> fGlyphArray;
SkChunkAlloc fGlyphAlloc; SkChunkAlloc fGlyphAlloc;
SkChunkAlloc fImageAlloc;
int fMetricsCount, fAdvanceCount; int fMetricsCount, fAdvanceCount;

View File

@ -14,22 +14,27 @@ static void test_chunkalloc(skiatest::Reporter* reporter) {
SkChunkAlloc alloc(min); SkChunkAlloc alloc(min);
REPORTER_ASSERT(reporter, 0 == alloc.totalCapacity()); REPORTER_ASSERT(reporter, 0 == alloc.totalCapacity());
REPORTER_ASSERT(reporter, 0 == alloc.totalUsed());
REPORTER_ASSERT(reporter, 0 == alloc.blockCount()); REPORTER_ASSERT(reporter, 0 == alloc.blockCount());
REPORTER_ASSERT(reporter, !alloc.contains(NULL)); REPORTER_ASSERT(reporter, !alloc.contains(NULL));
REPORTER_ASSERT(reporter, !alloc.contains(reporter)); REPORTER_ASSERT(reporter, !alloc.contains(reporter));
alloc.reset(); alloc.reset();
REPORTER_ASSERT(reporter, 0 == alloc.totalCapacity()); REPORTER_ASSERT(reporter, 0 == alloc.totalCapacity());
REPORTER_ASSERT(reporter, 0 == alloc.totalUsed());
REPORTER_ASSERT(reporter, 0 == alloc.blockCount()); REPORTER_ASSERT(reporter, 0 == alloc.blockCount());
size_t size = min >> 1; size_t size = min >> 1;
void* ptr = alloc.allocThrow(size); void* ptr = alloc.allocThrow(size);
REPORTER_ASSERT(reporter, alloc.totalCapacity() >= size); REPORTER_ASSERT(reporter, alloc.totalCapacity() >= size);
REPORTER_ASSERT(reporter, alloc.totalUsed() == size);
REPORTER_ASSERT(reporter, alloc.blockCount() > 0); REPORTER_ASSERT(reporter, alloc.blockCount() > 0);
REPORTER_ASSERT(reporter, alloc.contains(ptr)); REPORTER_ASSERT(reporter, alloc.contains(ptr));
alloc.reset(); alloc.reset();
REPORTER_ASSERT(reporter, !alloc.contains(ptr)); REPORTER_ASSERT(reporter, !alloc.contains(ptr));
REPORTER_ASSERT(reporter, 0 == alloc.totalCapacity());
REPORTER_ASSERT(reporter, 0 == alloc.totalUsed());
} }
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////