diff options
author | 2023-03-27 23:03:49 -0600 | |
---|---|---|
committer | 2023-04-03 15:05:48 -0600 | |
commit | f2588a8172a8481e4989924098eafa08a145b5c1 (patch) | |
tree | 3eca8330e2d880e2fb1bf1d5959f56739350870a | |
parent | be16373f15a245b4c14ad4f84b20ff8e76741893 (diff) |
EGL BlobCache: Trim immediately on multifile overflow
While adding a fuzzer for this feature, discovered that
cache trimming wasn't happening right when the overflow
happened, but on the next iteration.
This CL updates the code to make it trim right away, since
we've already determined it needs to happen.
Also add a test to ensure trimming happens right away.
Test: /data/nativetest64/EGL_test/EGL_test
Bug: b/266725576
Change-Id: Ica1e9ca688268e7e746750c27acdfced04e74b06
-rw-r--r-- | opengl/libs/EGL/MultifileBlobCache.cpp | 23 | ||||
-rw-r--r-- | opengl/libs/EGL/MultifileBlobCache.h | 2 | ||||
-rw-r--r-- | opengl/tests/EGLTest/egl_cache_test.cpp | 59 |
3 files changed, 66 insertions, 18 deletions
diff --git a/opengl/libs/EGL/MultifileBlobCache.cpp b/opengl/libs/EGL/MultifileBlobCache.cpp index f1b7a5c064..1c0c045bb4 100644 --- a/opengl/libs/EGL/MultifileBlobCache.cpp +++ b/opengl/libs/EGL/MultifileBlobCache.cpp @@ -267,7 +267,7 @@ void MultifileBlobCache::set(const void* key, EGLsizeiANDROID keySize, const voi // If we're going to be over the cache limit, kick off a trim to clear space if (getTotalSize() + fileSize > mMaxTotalSize) { ALOGV("SET: Cache is full, calling trimCache to clear space"); - trimCache(mMaxTotalSize); + trimCache(); } ALOGV("SET: Add %u to cache", entryHash); @@ -589,7 +589,7 @@ bool MultifileBlobCache::applyLRU(size_t cacheLimit) { } } - ALOGV("LRU: Cache is emptry"); + ALOGV("LRU: Cache is empty"); return false; } @@ -598,24 +598,15 @@ bool MultifileBlobCache::applyLRU(size_t cacheLimit) { constexpr uint32_t kCacheLimitDivisor = 2; // Calculate the cache size and remove old entries until under the limit -void MultifileBlobCache::trimCache(size_t cacheByteLimit) { - // Start with the value provided by egl_cache - size_t limit = cacheByteLimit; - +void MultifileBlobCache::trimCache() { // Wait for all deferred writes to complete ALOGV("TRIM: Waiting for work to complete."); waitForWorkComplete(); - size_t size = getTotalSize(); - - // If size is larger than the threshold, remove files using LRU - if (size > limit) { - ALOGV("TRIM: Multifile cache size is larger than %zu, removing old entries", - cacheByteLimit); - if (!applyLRU(limit / kCacheLimitDivisor)) { - ALOGE("Error when clearing multifile shader cache"); - return; - } + ALOGV("TRIM: Reducing multifile cache size to %zu", mMaxTotalSize / kCacheLimitDivisor); + if (!applyLRU(mMaxTotalSize / kCacheLimitDivisor)) { + ALOGE("Error when clearing multifile shader cache"); + return; } } diff --git a/opengl/libs/EGL/MultifileBlobCache.h b/opengl/libs/EGL/MultifileBlobCache.h index b461ef4fc6..f266011fda 100644 --- a/opengl/libs/EGL/MultifileBlobCache.h +++ b/opengl/libs/EGL/MultifileBlobCache.h @@ -119,7 +119,7 @@ private: bool addToHotCache(uint32_t entryHash, int fd, uint8_t* entryBufer, size_t entrySize); bool removeFromHotCache(uint32_t entryHash); - void trimCache(size_t cacheByteLimit); + void trimCache(); bool applyLRU(size_t cacheLimit); bool mInitialized; diff --git a/opengl/tests/EGLTest/egl_cache_test.cpp b/opengl/tests/EGLTest/egl_cache_test.cpp index ff4022cfe5..f81c68f66e 100644 --- a/opengl/tests/EGLTest/egl_cache_test.cpp +++ b/opengl/tests/EGLTest/egl_cache_test.cpp @@ -265,11 +265,68 @@ TEST_P(EGLCacheTest, TerminatedCacheBelowCacheLimit) { // Cache should contain both the key and the value // So 8 bytes per entry, at least 24 bytes ASSERT_GE(mCache->getCacheSize(), 24); - mCache->setCacheLimit(4); + + // Set the new limit and initialize cache mCache->terminate(); + mCache->setCacheLimit(4); + mCache->initialize(egl_display_t::get(EGL_DEFAULT_DISPLAY)); + + // Ensure the new limit is respected ASSERT_LE(mCache->getCacheSize(), 4); } +TEST_P(EGLCacheTest, TrimCacheOnOverflow) { + // Skip if not in multifile mode + if (mCacheMode == egl_cache_t::EGLCacheMode::Monolithic) { + GTEST_SKIP() << "Skipping test designed for multifile"; + } + + uint8_t buf[4] = { 0xee, 0xee, 0xee, 0xee }; + mCache->initialize(egl_display_t::get(EGL_DEFAULT_DISPLAY)); + + // Set one value in the cache + mCache->setBlob("abcd", 4, "efgh", 4); + ASSERT_EQ(4, mCache->getBlob("abcd", 4, buf, 4)); + ASSERT_EQ('e', buf[0]); + ASSERT_EQ('f', buf[1]); + ASSERT_EQ('g', buf[2]); + ASSERT_EQ('h', buf[3]); + + // Get the size of cache with a single entry + size_t cacheEntrySize = mCache->getCacheSize(); + + // Now reinitialize the cache, using max size equal to a single entry + mCache->terminate(); + mCache->setCacheLimit(cacheEntrySize); + mCache->initialize(egl_display_t::get(EGL_DEFAULT_DISPLAY)); + + // Ensure our cache still has original value + ASSERT_EQ(4, mCache->getBlob("abcd", 4, buf, 4)); + ASSERT_EQ('e', buf[0]); + ASSERT_EQ('f', buf[1]); + ASSERT_EQ('g', buf[2]); + ASSERT_EQ('h', buf[3]); + + // Set another value, which should overflow the cache and trim + mCache->setBlob("ijkl", 4, "mnop", 4); + ASSERT_EQ(4, mCache->getBlob("ijkl", 4, buf, 4)); + ASSERT_EQ('m', buf[0]); + ASSERT_EQ('n', buf[1]); + ASSERT_EQ('o', buf[2]); + ASSERT_EQ('p', buf[3]); + + // The cache should still be under the limit + ASSERT_TRUE(mCache->getCacheSize() == cacheEntrySize); + + // And no cache hit on trimmed entry + uint8_t buf2[4] = { 0xee, 0xee, 0xee, 0xee }; + mCache->getBlob("abcd", 4, buf2, 4); + ASSERT_EQ(0xee, buf2[0]); + ASSERT_EQ(0xee, buf2[1]); + ASSERT_EQ(0xee, buf2[2]); + ASSERT_EQ(0xee, buf2[3]); +} + INSTANTIATE_TEST_CASE_P(MonolithicCacheTests, EGLCacheTest, ::testing::Values(egl_cache_t::EGLCacheMode::Monolithic)); INSTANTIATE_TEST_CASE_P(MultifileCacheTests, |