Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(73)

Unified Diff: src/core/SkGlyphCache.cpp

Issue 24447003: add counting to glyphcache, and refactor some for clarity (Closed) Base URL: https://skia.googlecode.com/svn/trunk
Patch Set: expose count-limit in SkGraphics.h Created 7 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/core/SkGlyphCache.h ('k') | src/core/SkGlyphCache_Globals.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/core/SkGlyphCache.cpp
diff --git a/src/core/SkGlyphCache.cpp b/src/core/SkGlyphCache.cpp
index 538c9682f529848f438ddc5a1e0f1c18af2cda14..9dd235c1118564f1ad4e5c07a68abf83e36ba297 100644
--- a/src/core/SkGlyphCache.cpp
+++ b/src/core/SkGlyphCache.cpp
@@ -8,6 +8,7 @@
#include "SkGlyphCache.h"
+#include "SkGlyphCache_Globals.h"
#include "SkGraphics.h"
#include "SkPaint.h"
#include "SkPath.h"
@@ -20,6 +21,20 @@
bool gSkSuppressFontCachePurgeSpew;
+// Returns the shared globals
+static SkGlyphCache_Globals& getSharedGlobals() {
+ // we leak this, so we don't incur any shutdown cost of the destructor
+ static SkGlyphCache_Globals* gGlobals = SkNEW_ARGS(SkGlyphCache_Globals,
+ (SkGlyphCache_Globals::kYes_UseMutex));
+ return *gGlobals;
+}
+
+// Returns the TLS globals (if set), or the shared globals
+static SkGlyphCache_Globals& getGlobals() {
+ SkGlyphCache_Globals* tls = SkGlyphCache_Globals::FindTLS();
+ return tls ? *tls : getSharedGlobals();
+}
+
///////////////////////////////////////////////////////////////////////////////
#ifdef RECORD_HASH_EFFICIENCY
@@ -397,108 +412,38 @@ void SkGlyphCache::invokeAndRemoveAuxProcs() {
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
-#ifndef SK_DEFAULT_FONT_CACHE_LIMIT
- #define SK_DEFAULT_FONT_CACHE_LIMIT (2 * 1024 * 1024)
-#endif
-
#include "SkThread.h"
-class SkGlyphCache_Globals {
-public:
- enum UseMutex {
- kNo_UseMutex, // thread-local cache
- kYes_UseMutex // shared cache
- };
-
- SkGlyphCache_Globals(UseMutex um) {
- fHead = NULL;
- fTotalMemoryUsed = 0;
- fFontCacheLimit = SK_DEFAULT_FONT_CACHE_LIMIT;
- fMutex = (kYes_UseMutex == um) ? SkNEW(SkMutex) : NULL;
- }
-
- ~SkGlyphCache_Globals() {
- SkGlyphCache* cache = fHead;
- while (cache) {
- SkGlyphCache* next = cache->fNext;
- SkDELETE(cache);
- cache = next;
- }
-
- SkDELETE(fMutex);
- }
-
- SkMutex* fMutex;
- SkGlyphCache* fHead;
- size_t fTotalMemoryUsed;
-
-#ifdef SK_DEBUG
- void validate() const;
-#else
- void validate() const {}
-#endif
-
- size_t getFontCacheLimit() const { return fFontCacheLimit; }
- size_t setFontCacheLimit(size_t limit);
- void purgeAll(); // does not change budget
-
- // can return NULL
- static SkGlyphCache_Globals* FindTLS() {
- return (SkGlyphCache_Globals*)SkTLS::Find(CreateTLS);
- }
-
- static SkGlyphCache_Globals& GetTLS() {
- return *(SkGlyphCache_Globals*)SkTLS::Get(CreateTLS, DeleteTLS);
- }
-
- static void DeleteTLS() { SkTLS::Delete(CreateTLS); }
-
-private:
- size_t fFontCacheLimit;
-
- static void* CreateTLS() {
- return SkNEW_ARGS(SkGlyphCache_Globals, (kNo_UseMutex));
- }
-
- static void DeleteTLS(void* ptr) {
- SkDELETE((SkGlyphCache_Globals*)ptr);
- }
-};
-
-size_t SkGlyphCache_Globals::setFontCacheLimit(size_t newLimit) {
+size_t SkGlyphCache_Globals::setCacheSizeLimit(size_t newLimit) {
static const size_t minLimit = 256 * 1024;
if (newLimit < minLimit) {
newLimit = minLimit;
}
-
- size_t prevLimit = fFontCacheLimit;
- fFontCacheLimit = newLimit;
-
- size_t currUsed = fTotalMemoryUsed;
- if (currUsed > newLimit) {
- SkAutoMutexAcquire ac(fMutex);
- SkGlyphCache::InternalFreeCache(this, currUsed - newLimit);
- }
+
+ SkAutoMutexAcquire ac(fMutex);
+
+ size_t prevLimit = fCacheSizeLimit;
+ fCacheSizeLimit = newLimit;
+ this->internalPurge();
return prevLimit;
}
-void SkGlyphCache_Globals::purgeAll() {
+int SkGlyphCache_Globals::setCacheCountLimit(int newCount) {
+ if (newCount < 0) {
+ newCount = 0;
+ }
+
SkAutoMutexAcquire ac(fMutex);
- SkGlyphCache::InternalFreeCache(this, fTotalMemoryUsed);
+
+ int prevCount = fCacheCountLimit;
+ fCacheCountLimit = newCount;
+ this->internalPurge();
+ return prevCount;
}
-// Returns the shared globals
-static SkGlyphCache_Globals& getSharedGlobals() {
- // we leak this, so we don't incur any shutdown cost of the destructor
- static SkGlyphCache_Globals* gGlobals = SkNEW_ARGS(SkGlyphCache_Globals,
- (SkGlyphCache_Globals::kYes_UseMutex));
- return *gGlobals;
-}
-
-// Returns the TLS globals (if set), or the shared globals
-static SkGlyphCache_Globals& getGlobals() {
- SkGlyphCache_Globals* tls = SkGlyphCache_Globals::FindTLS();
- return tls ? *tls : getSharedGlobals();
+void SkGlyphCache_Globals::purgeAll() {
+ SkAutoMutexAcquire ac(fMutex);
+ this->internalPurge(fTotalMemoryUsed);
}
void SkGlyphCache::VisitAllCaches(bool (*proc)(SkGlyphCache*, void*),
@@ -509,7 +454,7 @@ void SkGlyphCache::VisitAllCaches(bool (*proc)(SkGlyphCache*, void*),
globals.validate();
- for (cache = globals.fHead; cache != NULL; cache = cache->fNext) {
+ for (cache = globals.internalGetHead(); cache != NULL; cache = cache->fNext) {
if (proc(cache, context)) {
break;
}
@@ -540,9 +485,9 @@ SkGlyphCache* SkGlyphCache::VisitCache(SkTypeface* typeface,
globals.validate();
- for (cache = globals.fHead; cache != NULL; cache = cache->fNext) {
+ for (cache = globals.internalGetHead(); cache != NULL; cache = cache->fNext) {
if (cache->fDesc->equals(*desc)) {
- cache->detach(&globals.fHead);
+ globals.internalDetachCache(cache);
goto FOUND_IT;
}
}
@@ -572,16 +517,11 @@ FOUND_IT:
AutoValidate av(cache);
- if (proc(cache, context)) { // stay detached
- if (insideMutex) {
- SkASSERT(globals.fTotalMemoryUsed >= cache->fMemoryUsed);
- globals.fTotalMemoryUsed -= cache->fMemoryUsed;
- }
- } else { // reattach
+ if (!proc(cache, context)) { // need to reattach
if (insideMutex) {
- cache->attachToHead(&globals.fHead);
+ globals.internalAttachCacheToHead(cache);
} else {
- AttachCache(cache);
+ globals.attachCacheToHead(cache);
}
cache = NULL;
}
@@ -592,30 +532,23 @@ void SkGlyphCache::AttachCache(SkGlyphCache* cache) {
SkASSERT(cache);
SkASSERT(cache->fNext == NULL);
- SkGlyphCache_Globals& globals = getGlobals();
- SkAutoMutexAcquire ac(globals.fMutex);
+ getGlobals().attachCacheToHead(cache);
+}
- globals.validate();
- cache->validate();
+///////////////////////////////////////////////////////////////////////////////
- // if we have a fixed budget for our cache, do a purge here
- {
- size_t allocated = globals.fTotalMemoryUsed + cache->fMemoryUsed;
- size_t budgeted = globals.getFontCacheLimit();
- if (allocated > budgeted) {
- (void)InternalFreeCache(&globals, allocated - budgeted);
- }
- }
+void SkGlyphCache_Globals::attachCacheToHead(SkGlyphCache* cache) {
+ SkAutoMutexAcquire ac(fMutex);
- cache->attachToHead(&globals.fHead);
- globals.fTotalMemoryUsed += cache->fMemoryUsed;
+ this->validate();
+ cache->validate();
- globals.validate();
+ this->internalAttachCacheToHead(cache);
+ this->internalPurge();
}
-///////////////////////////////////////////////////////////////////////////////
-
-SkGlyphCache* SkGlyphCache::FindTail(SkGlyphCache* cache) {
+SkGlyphCache* SkGlyphCache_Globals::internalGetTail() const {
+ SkGlyphCache* cache = fHead;
if (cache) {
while (cache->fNext) {
cache = cache->fNext;
@@ -624,63 +557,92 @@ SkGlyphCache* SkGlyphCache::FindTail(SkGlyphCache* cache) {
return cache;
}
-#ifdef SK_DEBUG
-void SkGlyphCache_Globals::validate() const {
- size_t computed = 0;
+size_t SkGlyphCache_Globals::internalPurge(size_t minBytesNeeded) {
+ this->validate();
- const SkGlyphCache* head = fHead;
- while (head != NULL) {
- computed += head->fMemoryUsed;
- head = head->fNext;
+ size_t bytesNeeded = 0;
+ if (fTotalMemoryUsed > fCacheSizeLimit) {
+ bytesNeeded = fTotalMemoryUsed - fCacheSizeLimit;
+ }
+ bytesNeeded = SkMax32(bytesNeeded, minBytesNeeded);
+ if (bytesNeeded) {
+ // no small purges!
+ bytesNeeded = SkMax32(bytesNeeded, fTotalMemoryUsed >> 2);
}
- if (fTotalMemoryUsed != computed) {
- printf("total %d, computed %d\n", (int)fTotalMemoryUsed, (int)computed);
+ int countNeeded = 0;
+ if (fCacheCount > fCacheCountLimit) {
+ countNeeded = fCacheCount - fCacheCountLimit;
+ // no small purges!
+ countNeeded = SkMax32(countNeeded, fCacheCount >> 2);
}
- SkASSERT(fTotalMemoryUsed == computed);
-}
-#endif
-size_t SkGlyphCache::InternalFreeCache(SkGlyphCache_Globals* globals,
- size_t bytesNeeded) {
- globals->validate();
+ // early exit
+ if (!countNeeded && !bytesNeeded) {
+ return 0;
+ }
size_t bytesFreed = 0;
- int count = 0;
-
- // don't do any "small" purges
- size_t minToPurge = globals->fTotalMemoryUsed >> 2;
- if (bytesNeeded < minToPurge)
- bytesNeeded = minToPurge;
+ int countFreed = 0;
- SkGlyphCache* cache = FindTail(globals->fHead);
- while (cache != NULL && bytesFreed < bytesNeeded) {
+ // we start at the tail and proceed backwards, as the linklist is in LRU
+ // order, with unimportant entries at the tail.
+ SkGlyphCache* cache = this->internalGetTail();
+ while (cache != NULL &&
+ (bytesFreed < bytesNeeded || countFreed < countNeeded)) {
SkGlyphCache* prev = cache->fPrev;
bytesFreed += cache->fMemoryUsed;
+ countFreed += 1;
- cache->detach(&globals->fHead);
+ this->internalDetachCache(cache);
SkDELETE(cache);
cache = prev;
- count += 1;
}
- SkASSERT(bytesFreed <= globals->fTotalMemoryUsed);
- globals->fTotalMemoryUsed -= bytesFreed;
- globals->validate();
+ this->validate();
#ifdef SPEW_PURGE_STATUS
- if (count && !gSkSuppressFontCachePurgeSpew) {
+ if (countFreed && !gSkSuppressFontCachePurgeSpew) {
SkDebugf("purging %dK from font cache [%d entries]\n",
- (int)(bytesFreed >> 10), count);
+ (int)(bytesFreed >> 10), countFreed);
}
#endif
return bytesFreed;
}
+void SkGlyphCache_Globals::internalAttachCacheToHead(SkGlyphCache* cache) {
+ SkASSERT(NULL == cache->fPrev && NULL == cache->fNext);
+ if (fHead) {
+ fHead->fPrev = cache;
+ cache->fNext = fHead;
+ }
+ fHead = cache;
+
+ fCacheCount += 1;
+ fTotalMemoryUsed += cache->fMemoryUsed;
+}
+
+void SkGlyphCache_Globals::internalDetachCache(SkGlyphCache* cache) {
+ SkASSERT(fCacheCount > 0);
+ fCacheCount -= 1;
+ fTotalMemoryUsed -= cache->fMemoryUsed;
+
+ if (cache->fPrev) {
+ cache->fPrev->fNext = cache->fNext;
+ } else {
+ fHead = cache->fNext;
+ }
+ if (cache->fNext) {
+ cache->fNext->fPrev = cache->fPrev;
+ }
+ cache->fPrev = cache->fNext = NULL;
+}
+
///////////////////////////////////////////////////////////////////////////////
#ifdef SK_DEBUG
+
void SkGlyphCache::validate() const {
#ifdef SK_DEBUG_GLYPH_CACHE
int count = fGlyphArray.count();
@@ -694,6 +656,22 @@ void SkGlyphCache::validate() const {
}
#endif
}
+
+void SkGlyphCache_Globals::validate() const {
+ size_t computedBytes = 0;
+ int computedCount = 0;
+
+ const SkGlyphCache* head = fHead;
+ while (head != NULL) {
+ computedBytes += head->fMemoryUsed;
+ computedCount += 1;
+ head = head->fNext;
+ }
+
+ SkASSERT(fTotalMemoryUsed == computedBytes);
+ SkASSERT(fCacheCount == computedCount);
+}
+
#endif
///////////////////////////////////////////////////////////////////////////////
@@ -702,15 +680,27 @@ void SkGlyphCache::validate() const {
#include "SkTypefaceCache.h"
size_t SkGraphics::GetFontCacheLimit() {
- return getSharedGlobals().getFontCacheLimit();
+ return getSharedGlobals().getCacheSizeLimit();
}
size_t SkGraphics::SetFontCacheLimit(size_t bytes) {
- return getSharedGlobals().setFontCacheLimit(bytes);
+ return getSharedGlobals().setCacheSizeLimit(bytes);
}
size_t SkGraphics::GetFontCacheUsed() {
- return getSharedGlobals().fTotalMemoryUsed;
+ return getSharedGlobals().getTotalMemoryUsed();
+}
+
+int SkGraphics::GetFontCacheCountLimit() {
+ return getSharedGlobals().getCacheCountLimit();
+}
+
+int SkGraphics::SetFontCacheCountLimit(int count) {
+ return getSharedGlobals().setCacheCountLimit(count);
+}
+
+int SkGraphics::GetFontCacheCountUsed() {
+ return getSharedGlobals().getCacheCountUsed();
}
void SkGraphics::PurgeFontCache() {
@@ -720,13 +710,13 @@ void SkGraphics::PurgeFontCache() {
size_t SkGraphics::GetTLSFontCacheLimit() {
const SkGlyphCache_Globals* tls = SkGlyphCache_Globals::FindTLS();
- return tls ? tls->getFontCacheLimit() : 0;
+ return tls ? tls->getCacheSizeLimit() : 0;
}
void SkGraphics::SetTLSFontCacheLimit(size_t bytes) {
if (0 == bytes) {
SkGlyphCache_Globals::DeleteTLS();
} else {
- SkGlyphCache_Globals::GetTLS().setFontCacheLimit(bytes);
+ SkGlyphCache_Globals::GetTLS().setCacheSizeLimit(bytes);
}
}
« no previous file with comments | « src/core/SkGlyphCache.h ('k') | src/core/SkGlyphCache_Globals.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698