diff options
author | bsalomon <bsalomon@google.com> | 2016-10-03 14:07:01 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2016-10-03 14:07:01 -0700 |
commit | 0f147ac2ae575bbad3515a526f13700bc5c8e9d7 (patch) | |
tree | c5a3f893dec0881746d1d0eeb06a7ad589ac186c /src/gpu/GrResourceCache.h | |
parent | e60d85597f803c4dff6329840215af1d1d9a8fdc (diff) |
Make GrResourceCache dynamically change between LRU and random replacement strategies.
Random performs significantly better when each frame exceeds the budget by a small margin whereas LRU has worst case behavior.
The decision of which to use is made based on the history from a few frames of the ratio of total unique key cache misses to unique key cache misses of resources purged in the last 2 frames.
GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2321563006
Review-Url: https://codereview.chromium.org/2321563006
Diffstat (limited to 'src/gpu/GrResourceCache.h')
-rw-r--r-- | src/gpu/GrResourceCache.h | 70 |
1 files changed, 54 insertions, 16 deletions
diff --git a/src/gpu/GrResourceCache.h b/src/gpu/GrResourceCache.h index ae9a4e7ee7..d6cdf81612 100644 --- a/src/gpu/GrResourceCache.h +++ b/src/gpu/GrResourceCache.h @@ -13,7 +13,9 @@ #include "GrGpuResourcePriv.h" #include "GrResourceCache.h" #include "GrResourceKey.h" +#include "SkChunkAlloc.h" #include "SkMessageBus.h" +#include "SkRandom.h" #include "SkRefCnt.h" #include "SkTArray.h" #include "SkTDPQueue.h" @@ -137,13 +139,7 @@ public: /** * Find a resource that matches a unique key. */ - GrGpuResource* findAndRefUniqueResource(const GrUniqueKey& key) { - GrGpuResource* resource = fUniqueHash.find(key); - if (resource) { - this->refAndMakeResourceMRU(resource); - } - return resource; - } + GrGpuResource* findAndRefUniqueResource(const GrUniqueKey& key); /** * Query whether a unique key exists in the cache. @@ -154,14 +150,19 @@ public: /** Purges resources to become under budget and processes resources with invalidated unique keys. */ - void purgeAsNeeded(); + void purgeAsNeeded() { this->internalPurgeAsNeeded(false); } /** Purges all resources that don't have external owners. */ void purgeAllUnlocked(); /** Returns true if the cache would like a flush to occur in order to make more resources purgeable. */ - bool requestsFlush() const { return fRequestFlush; } + bool requestsFlush() const { + // When in random replacement mode we request a flush in order to make as many resources + // as possible subject to replacement. + return this->overBudget() && (ReplacementStrategy::kRandom == fStrategy || + 0 == fPurgeableQueue.count()); + } enum FlushType { kExternal, @@ -232,10 +233,14 @@ private: void refAndMakeResourceMRU(GrGpuResource*); /// @} + void internalPurgeAsNeeded(bool fromFlushNotification); void processInvalidUniqueKeys(const SkTArray<GrUniqueKeyInvalidatedMessage>&); void addToNonpurgeableArray(GrGpuResource*); void removeFromNonpurgeableArray(GrGpuResource*); bool overBudget() const { return fBudgetedBytes > fMaxBytes || fBudgetedCount > fMaxCount; } + GrGpuResource* selectResourceUsingStrategy(); + void recordPurgedKey(GrGpuResource*); + void recordKeyMiss(const GrUniqueKey&); bool wouldFit(size_t bytes) { return fBudgetedBytes+bytes <= fMaxBytes && fBudgetedCount+1 <= fMaxCount; @@ -254,22 +259,27 @@ private: class AvailableForScratchUse; - struct ScratchMapTraits { + struct HashTraitsBase { + static uint32_t Hash(const GrResourceKey& key) { return key.hash(); } + }; + + struct ScratchMapTraits : public HashTraitsBase { static const GrScratchKey& GetKey(const GrGpuResource& r) { return r.resourcePriv().getScratchKey(); } - - static uint32_t Hash(const GrScratchKey& key) { return key.hash(); } }; typedef SkTMultiMap<GrGpuResource, GrScratchKey, ScratchMapTraits> ScratchMap; - struct UniqueHashTraits { + struct UniqueHashTraits : public HashTraitsBase { static const GrUniqueKey& GetKey(const GrGpuResource& r) { return r.getUniqueKey(); } - - static uint32_t Hash(const GrUniqueKey& key) { return key.hash(); } }; typedef SkTDynamicHash<GrGpuResource, GrUniqueKey, UniqueHashTraits> UniqueHash; + struct UniqueSetTraits : public HashTraitsBase { + static const GrUniqueKey& GetKey(const GrUniqueKey& key) { return key; } + }; + typedef SkTDynamicHash<GrUniqueKey, GrUniqueKey, UniqueSetTraits> UniqueKeySet; + static bool CompareTimestamp(GrGpuResource* const& a, GrGpuResource* const& b) { return a->cacheAccess().timestamp() < b->cacheAccess().timestamp(); } @@ -278,6 +288,22 @@ private: return res->cacheAccess().accessCacheIndex(); } + /** + * The resource cache chooses one of these replacement strategies based on a "strategy score" + * updated after each external flush based on unique key cache misses. + */ + enum class ReplacementStrategy { + kLRU, + kRandom + }; + /** + * When the current strategy score is >=0 LRU is chosen, when it is < 0 random is chosen. The + * absolute value of the score moves by 1 each flush. + */ + static constexpr int kStrategyScoreMin = -5; + static constexpr int kStrategyScoreMax = 4; + static constexpr int kInitialStrategyScore = 2; + typedef SkMessageBus<GrUniqueKeyInvalidatedMessage>::Inbox InvalidUniqueKeyInbox; typedef SkTDPQueue<GrGpuResource*, CompareTimestamp, AccessResourceIndex> PurgeableQueue; typedef SkTDArray<GrGpuResource*> ResourceArray; @@ -299,6 +325,17 @@ private: size_t fMaxBytes; int fMaxUnusedFlushes; + // Data related to replacement strategy. + SkRandom fRandom; + ReplacementStrategy fStrategy; + int fStrategyScore; + int fTotalMissesThisFlush; + int fMissesThisFlushPurgedRecently; + UniqueKeySet fUniqueKeysPurgedThisFlush[2]; + // These are pointers to SkChunckAlloc because of gcc bug 63707 + SkChunkAlloc* fUniqueKeysPurgedThisFlushStorage[2]; + int fFlushParity; + #if GR_CACHE_STATS int fHighWaterCount; size_t fHighWaterBytes; @@ -314,9 +351,10 @@ private: int fBudgetedCount; size_t fBudgetedBytes; - bool fRequestFlush; uint32_t fExternalFlushCnt; + bool fIsPurging; + InvalidUniqueKeyInbox fInvalidUniqueKeyInbox; // This resource is allowed to be in the nonpurgeable array for the sake of validate() because |