reduce mutex use and switch to spinlock

* Combine find and makeMRU.
* Switch from SkMutex to SkSpinLock

In the gm 'paragraph_$' this reduces acquiring the lock from 1.2% to 0.7%
as measured by instruments and nanobench.

Change-Id: I33e3af31825f175c9de42f001acf68ffe3623a8a
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/305564
Reviewed-by: Ben Wagner <bungeman@google.com>
Commit-Queue: Herb Derby <herb@google.com>
This commit is contained in:
Herb Derby 2020-07-23 13:24:53 -04:00 committed by Skia Commit-Bot
parent b6d4ad92ad
commit 13e3faebc6
4 changed files with 39 additions and 45 deletions

View File

@ -482,11 +482,7 @@ void GrRenderTargetContext::drawGlyphRunList(const GrClip* clip,
}
const SkMatrix& drawMatrix(viewMatrix.localToDevice());
if (blob != nullptr && blob->canReuse(blobPaint, blurRec, drawMatrix, drawOrigin)) {
// Reusing the blob. Move it to the front of LRU cache.
textBlobCache->makeMRU(blob.get());
} else {
// Build or Rebuild the GrTextBlob
if (blob == nullptr || !blob->canReuse(blobPaint, blurRec, drawMatrix, drawOrigin)) {
if (blob != nullptr) {
// We have to remake the blob because changes may invalidate our masks.
// TODO we could probably get away with reuse most of the time if the pointer is unique,

View File

@ -26,20 +26,30 @@ GrTextBlobCache::makeCachedBlob(const SkGlyphRunList& glyphRunList, const GrText
const SkMatrix& viewMatrix) {
sk_sp<GrTextBlob> cacheBlob(GrTextBlob::Make(glyphRunList, viewMatrix));
cacheBlob->setupKey(key, blurRec, glyphRunList.paint());
SkAutoMutexExclusive lock{fMutex};
SkAutoSpinlock lock{fSpinLock};
this->internalAdd(cacheBlob);
glyphRunList.temporaryShuntBlobNotifyAddedToCache(fMessageBusID);
return cacheBlob;
}
sk_sp<GrTextBlob> GrTextBlobCache::find(const GrTextBlob::Key& key) const {
SkAutoMutexExclusive lock{fMutex};
const auto* idEntry = fBlobIDCache.find(key.fUniqueID);
return idEntry ? idEntry->find(key) : nullptr;
sk_sp<GrTextBlob> GrTextBlobCache::find(const GrTextBlob::Key& key) {
SkAutoSpinlock lock{fSpinLock};
const BlobIDCacheEntry* idEntry = fBlobIDCache.find(key.fUniqueID);
if (idEntry == nullptr) {
return nullptr;
}
sk_sp<GrTextBlob> blob = idEntry->find(key);
GrTextBlob* blobPtr = blob.get();
if (blobPtr != nullptr && blobPtr != fBlobList.head()) {
fBlobList.remove(blobPtr);
fBlobList.addToHead(blobPtr);
}
return blob;
}
void GrTextBlobCache::remove(GrTextBlob* blob) {
SkAutoMutexExclusive lock{fMutex};
SkAutoSpinlock lock{fSpinLock};
this->internalRemove(blob);
}
@ -56,18 +66,8 @@ void GrTextBlobCache::internalRemove(GrTextBlob* blob) {
}
}
void GrTextBlobCache::makeMRU(GrTextBlob* blob) {
SkAutoMutexExclusive lock{fMutex};
if (fBlobList.head() == blob) {
return;
}
fBlobList.remove(blob);
fBlobList.addToHead(blob);
}
void GrTextBlobCache::freeAll() {
SkAutoMutexExclusive lock{fMutex};
SkAutoSpinlock lock{fSpinLock};
fBlobIDCache.reset();
fBlobList.reset();
fCurrentSize = 0;
@ -79,7 +79,7 @@ void GrTextBlobCache::PostPurgeBlobMessage(uint32_t blobID, uint32_t cacheID) {
}
void GrTextBlobCache::purgeStaleBlobs() {
SkAutoMutexExclusive lock{fMutex};
SkAutoSpinlock lock{fSpinLock};
this->internalPurgeStaleBlobs();
}
@ -106,12 +106,12 @@ void GrTextBlobCache::internalPurgeStaleBlobs() {
}
size_t GrTextBlobCache::usedBytes() const {
SkAutoMutexExclusive lock{fMutex};
SkAutoSpinlock lock{fSpinLock};
return fCurrentSize;
}
bool GrTextBlobCache::isOverBudget() const {
SkAutoMutexExclusive lock{fMutex};
SkAutoSpinlock lock{fSpinLock};
return fCurrentSize > fSizeBudget;
}

View File

@ -25,15 +25,13 @@ public:
sk_sp<GrTextBlob> makeCachedBlob(const SkGlyphRunList& glyphRunList,
const GrTextBlob::Key& key,
const SkMaskFilterBase::BlurRec& blurRec,
const SkMatrix& viewMatrix) SK_EXCLUDES(fMutex);
const SkMatrix& viewMatrix) SK_EXCLUDES(fSpinLock);
sk_sp<GrTextBlob> find(const GrTextBlob::Key& key) const SK_EXCLUDES(fMutex);
sk_sp<GrTextBlob> find(const GrTextBlob::Key& key) SK_EXCLUDES(fSpinLock);
void remove(GrTextBlob* blob) SK_EXCLUDES(fMutex);
void remove(GrTextBlob* blob) SK_EXCLUDES(fSpinLock);
void makeMRU(GrTextBlob* blob) SK_EXCLUDES(fMutex);
void freeAll() SK_EXCLUDES(fMutex);
void freeAll() SK_EXCLUDES(fSpinLock);
struct PurgeBlobMessage {
PurgeBlobMessage(uint32_t blobID, uint32_t contextUniqueID)
@ -45,11 +43,11 @@ public:
static void PostPurgeBlobMessage(uint32_t blobID, uint32_t cacheID);
void purgeStaleBlobs() SK_EXCLUDES(fMutex);
void purgeStaleBlobs() SK_EXCLUDES(fSpinLock);
size_t usedBytes() const SK_EXCLUDES(fMutex);
size_t usedBytes() const SK_EXCLUDES(fSpinLock);
bool isOverBudget() const SK_EXCLUDES(fMutex);
bool isOverBudget() const SK_EXCLUDES(fSpinLock);
private:
friend class GrTextBlobTestingPeer;
@ -75,24 +73,24 @@ private:
SkSTArray<1, sk_sp<GrTextBlob>> fBlobs;
};
void internalPurgeStaleBlobs() SK_REQUIRES(fMutex);
void internalPurgeStaleBlobs() SK_REQUIRES(fSpinLock);
void internalAdd(sk_sp<GrTextBlob> blob) SK_REQUIRES(fMutex);
void internalRemove(GrTextBlob* blob) SK_REQUIRES(fMutex);
void internalAdd(sk_sp<GrTextBlob> blob) SK_REQUIRES(fSpinLock);
void internalRemove(GrTextBlob* blob) SK_REQUIRES(fSpinLock);
void internalCheckPurge(GrTextBlob* blob = nullptr) SK_REQUIRES(fMutex);
void internalCheckPurge(GrTextBlob* blob = nullptr) SK_REQUIRES(fSpinLock);
static const int kDefaultBudget = 1 << 22;
mutable SkMutex fMutex;
TextBlobList fBlobList SK_GUARDED_BY(fMutex);
SkTHashMap<uint32_t, BlobIDCacheEntry> fBlobIDCache SK_GUARDED_BY(fMutex);
size_t fSizeBudget SK_GUARDED_BY(fMutex);
size_t fCurrentSize SK_GUARDED_BY(fMutex) {0};
mutable SkSpinlock fSpinLock;
TextBlobList fBlobList SK_GUARDED_BY(fSpinLock);
SkTHashMap<uint32_t, BlobIDCacheEntry> fBlobIDCache SK_GUARDED_BY(fSpinLock);
size_t fSizeBudget SK_GUARDED_BY(fSpinLock);
size_t fCurrentSize SK_GUARDED_BY(fSpinLock) {0};
// In practice 'messageBusID' is always the unique ID of the owning GrContext
const uint32_t fMessageBusID;
SkMessageBus<PurgeBlobMessage>::Inbox fPurgeBlobInbox SK_GUARDED_BY(fMutex);
SkMessageBus<PurgeBlobMessage>::Inbox fPurgeBlobInbox SK_GUARDED_BY(fSpinLock);
};
#endif

View File

@ -55,7 +55,7 @@ static void setup_always_evict_atlas(GrDirectContext* dContext) {
class GrTextBlobTestingPeer {
public:
static void SetBudget(GrTextBlobCache* cache, size_t budget) {
SkAutoMutexExclusive lock{cache->fMutex};
SkAutoSpinlock lock{cache->fSpinLock};
cache->fSizeBudget = budget;
cache->internalCheckPurge();
}