summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Cody Northrop <cnorthrop@google.com> 2023-03-27 23:03:49 -0600
committer Cody Northrop <cnorthrop@google.com> 2023-04-03 15:05:48 -0600
commitf2588a8172a8481e4989924098eafa08a145b5c1 (patch)
tree3eca8330e2d880e2fb1bf1d5959f56739350870a
parentbe16373f15a245b4c14ad4f84b20ff8e76741893 (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.cpp23
-rw-r--r--opengl/libs/EGL/MultifileBlobCache.h2
-rw-r--r--opengl/tests/EGLTest/egl_cache_test.cpp59
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,