@@ -47,6 +47,11 @@ using namespace std::literals;
4747constexpr uint32_t kMultifileMagic = ' MFB$' ;
4848constexpr uint32_t kCrcPlaceholder = 0 ;
4949
50+ // When removing files, what fraction of the overall limit should be reached when removing files
51+ // A divisor of two will decrease the cache to 50%, four to 25% and so on
52+ // We use the same limit to manage size and entry count
53+ constexpr uint32_t kCacheLimitDivisor = 2 ;
54+
5055namespace {
5156
5257// Helper function to close entries or free them
@@ -76,6 +81,7 @@ MultifileBlobCache::MultifileBlobCache(size_t maxKeySize, size_t maxValueSize, s
7681 mMaxTotalEntries(maxTotalEntries),
7782 mTotalCacheSize(0 ),
7883 mTotalCacheEntries(0 ),
84+ mTotalCacheSizeDivisor(kCacheLimitDivisor ),
7985 mHotCacheLimit(0 ),
8086 mHotCacheSize(0 ),
8187 mWorkerThreadIdle(true ) {
@@ -247,7 +253,8 @@ MultifileBlobCache::MultifileBlobCache(size_t maxKeySize, size_t maxValueSize, s
247253 ALOGV (" INIT: Entry %u is good, tracking it now." , entryHash);
248254
249255 // Track details for rapid lookup later and update total size
250- trackEntry (entryHash, header.valueSize , fileSize, st.st_atime );
256+ // Note access time is a full timespec instead of just seconds
257+ trackEntry (entryHash, header.valueSize , fileSize, st.st_atim );
251258
252259 // Preload the entry for fast retrieval
253260 if ((mHotCacheSize + fileSize) < mHotCacheLimit ) {
@@ -357,7 +364,11 @@ void MultifileBlobCache::set(const void* key, EGLsizeiANDROID keySize, const voi
357364 std::string fullPath = mMultifileDirName + " /" + std::to_string (entryHash);
358365
359366 // Track the size and access time for quick recall and update the overall cache size
360- trackEntry (entryHash, valueSize, fileSize, time (0 ));
367+ struct timespec time = {0 , 0 };
368+ if (flags::multifile_blobcache_advanced_usage ()) {
369+ clock_gettime (CLOCK_REALTIME, &time);
370+ }
371+ trackEntry (entryHash, valueSize, fileSize, time);
361372
362373 // Keep the entry in hot cache for quick retrieval
363374 ALOGV (" SET: Adding %u to hot cache." , entryHash);
@@ -439,6 +450,14 @@ EGLsizeiANDROID MultifileBlobCache::get(const void* key, EGLsizeiANDROID keySize
439450 if (mHotCache .find (entryHash) != mHotCache .end ()) {
440451 ALOGV (" GET: HotCache HIT for entry %u" , entryHash);
441452 cacheEntry = mHotCache [entryHash].entryBuffer ;
453+
454+ if (flags::multifile_blobcache_advanced_usage ()) {
455+ // Update last access time on disk
456+ struct timespec times[2 ];
457+ times[0 ].tv_nsec = UTIME_NOW;
458+ times[1 ].tv_nsec = UTIME_OMIT;
459+ utimensat (0 , fullPath.c_str (), times, 0 );
460+ }
442461 } else {
443462 ALOGV (" GET: HotCache MISS for entry: %u" , entryHash);
444463
@@ -467,6 +486,14 @@ EGLsizeiANDROID MultifileBlobCache::get(const void* key, EGLsizeiANDROID keySize
467486 cacheEntry =
468487 reinterpret_cast <uint8_t *>(mmap (nullptr , fileSize, PROT_READ, MAP_PRIVATE, fd, 0 ));
469488
489+ if (flags::multifile_blobcache_advanced_usage ()) {
490+ // Update last access time and omit last modify time
491+ struct timespec times[2 ];
492+ times[0 ].tv_nsec = UTIME_NOW;
493+ times[1 ].tv_nsec = UTIME_OMIT;
494+ futimens (fd, times);
495+ }
496+
470497 // We can close the file now and the mmap will remain
471498 close (fd);
472499
@@ -503,6 +530,13 @@ EGLsizeiANDROID MultifileBlobCache::get(const void* key, EGLsizeiANDROID keySize
503530 return 0 ;
504531 }
505532
533+ if (flags::multifile_blobcache_advanced_usage ()) {
534+ // Update the entry time for this hash, so it reflects LRU
535+ struct timespec time;
536+ clock_gettime (CLOCK_REALTIME, &time);
537+ updateEntryTime (entryHash, time);
538+ }
539+
506540 // Remaining entry following the key is the value
507541 uint8_t * cachedValue = cacheEntry + (keySize + sizeof (MultifileHeader));
508542 memcpy (value, cachedValue, cachedValueSize);
@@ -638,9 +672,20 @@ bool MultifileBlobCache::checkStatus(const std::string& baseDir) {
638672}
639673
640674void MultifileBlobCache::trackEntry (uint32_t entryHash, EGLsizeiANDROID valueSize, size_t fileSize,
641- time_t accessTime) {
675+ const timespec& accessTime) {
676+ #if COM_ANDROID_GRAPHICS_EGL_FLAGS(MULTIFILE_BLOBCACHE_ADVANCED_USAGE)
677+ // When we add this entry to the map, it is sorted by accessTime
678+ MultifileEntryStatsMapIter entryStatsIter =
679+ mEntryStats .emplace (std::piecewise_construct, std::forward_as_tuple (accessTime),
680+ std::forward_as_tuple (entryHash, valueSize, fileSize));
681+
682+ // Track all entries with quick access to its stats
683+ mEntries .emplace (entryHash, entryStatsIter);
684+ #else
685+ (void )accessTime;
642686 mEntries .insert (entryHash);
643- mEntryStats [entryHash] = {valueSize, fileSize, accessTime};
687+ mEntryStats [entryHash] = {entryHash, valueSize, fileSize};
688+ #endif // COM_ANDROID_GRAPHICS_EGL_FLAGS(MULTIFILE_BLOBCACHE_ADVANCED_USAGE)
644689
645690 increaseTotalCacheSize (fileSize);
646691}
@@ -651,12 +696,18 @@ bool MultifileBlobCache::removeEntry(uint32_t entryHash) {
651696 return false ;
652697 }
653698
699+ #if COM_ANDROID_GRAPHICS_EGL_FLAGS(MULTIFILE_BLOBCACHE_ADVANCED_USAGE)
700+ MultifileEntryStatsMapIter entryStatsIter = entryIter->second ;
701+ MultifileEntryStats entryStats = entryStatsIter->second ;
702+ decreaseTotalCacheSize (entryStats.fileSize );
703+ #else
654704 auto entryStatsIter = mEntryStats .find (entryHash);
655705 if (entryStatsIter == mEntryStats .end ()) {
656706 ALOGE (" Failed to remove entryHash (%u) from mEntryStats" , entryHash);
657707 return false ;
658708 }
659709 decreaseTotalCacheSize (entryStatsIter->second .fileSize );
710+ #endif // COM_ANDROID_GRAPHICS_EGL_FLAGS(MULTIFILE_BLOBCACHE_ADVANCED_USAGE)
660711
661712 mEntryStats .erase (entryStatsIter);
662713 mEntries .erase (entryIter);
@@ -669,7 +720,40 @@ bool MultifileBlobCache::contains(uint32_t hashEntry) const {
669720}
670721
671722MultifileEntryStats MultifileBlobCache::getEntryStats (uint32_t entryHash) {
723+ #if COM_ANDROID_GRAPHICS_EGL_FLAGS(MULTIFILE_BLOBCACHE_ADVANCED_USAGE)
724+ auto entryIter = mEntries .find (entryHash);
725+ if (entryIter == mEntries .end ()) {
726+ return {};
727+ }
728+
729+ MultifileEntryStatsMapIter entryStatsIter = entryIter->second ;
730+ MultifileEntryStats entryStats = entryStatsIter->second ;
731+ return entryStats;
732+ #else
672733 return mEntryStats [entryHash];
734+ #endif // COM_ANDROID_GRAPHICS_EGL_FLAGS(MULTIFILE_BLOBCACHE_ADVANCED_USAGE)
735+ }
736+
737+ void MultifileBlobCache::updateEntryTime (uint32_t entryHash, const timespec& newTime) {
738+ #if COM_ANDROID_GRAPHICS_EGL_FLAGS(MULTIFILE_BLOBCACHE_ADVANCED_USAGE)
739+ // This function updates the ordering of the map by removing the old iterators
740+ // and re-adding them. If should be perforant as it does not perform a full re-sort.
741+ // First, pull out the old entryStats
742+ auto entryIter = mEntries .find (entryHash);
743+ MultifileEntryStatsMapIter entryStatsIter = entryIter->second ;
744+ MultifileEntryStats entryStats = std::move (entryStatsIter->second );
745+
746+ // Remove the old iterators
747+ mEntryStats .erase (entryStatsIter);
748+ mEntries .erase (entryIter);
749+
750+ // Insert the new with updated time
751+ entryStatsIter = mEntryStats .emplace (std::make_pair (newTime, std::move (entryStats)));
752+ mEntries .emplace (entryHash, entryStatsIter);
753+ #else
754+ (void )entryHash;
755+ (void )newTime;
756+ #endif // COM_ANDROID_GRAPHICS_EGL_FLAGS(MULTIFILE_BLOBCACHE_ADVANCED_USAGE)
673757}
674758
675759void MultifileBlobCache::increaseTotalCacheSize (size_t fileSize) {
@@ -751,8 +835,13 @@ bool MultifileBlobCache::removeFromHotCache(uint32_t entryHash) {
751835bool MultifileBlobCache::applyLRU (size_t cacheSizeLimit, size_t cacheEntryLimit) {
752836 // Walk through our map of sorted last access times and remove files until under the limit
753837 for (auto cacheEntryIter = mEntryStats .begin (); cacheEntryIter != mEntryStats .end ();) {
838+ #if COM_ANDROID_GRAPHICS_EGL_FLAGS(MULTIFILE_BLOBCACHE_ADVANCED_USAGE)
839+ const MultifileEntryStats& entryStats = cacheEntryIter->second ;
840+ uint32_t entryHash = entryStats.entryHash ;
841+ #else
754842 uint32_t entryHash = cacheEntryIter->first ;
755843 const MultifileEntryStats& entryStats = cacheEntryIter->second ;
844+ #endif // COM_ANDROID_GRAPHICS_EGL_FLAGS(MULTIFILE_BLOBCACHE_ADVANCED_USAGE)
756845
757846 ALOGV (" LRU: Removing entryHash %u" , entryHash);
758847
@@ -823,20 +912,17 @@ bool MultifileBlobCache::clearCache() {
823912 return true ;
824913}
825914
826- // When removing files, what fraction of the overall limit should be reached when removing files
827- // A divisor of two will decrease the cache to 50%, four to 25% and so on
828- // We use the same limit to manage size and entry count
829- constexpr uint32_t kCacheLimitDivisor = 2 ;
830-
831915// Calculate the cache size and remove old entries until under the limit
832916void MultifileBlobCache::trimCache () {
833917 // Wait for all deferred writes to complete
834918 ALOGV (" TRIM: Waiting for work to complete." );
835919 waitForWorkComplete ();
836920
837921 ALOGV (" TRIM: Reducing multifile cache size to %zu, entries %zu" ,
838- mMaxTotalSize / kCacheLimitDivisor , mMaxTotalEntries / kCacheLimitDivisor );
839- if (!applyLRU (mMaxTotalSize / kCacheLimitDivisor , mMaxTotalEntries / kCacheLimitDivisor )) {
922+ mMaxTotalSize / mTotalCacheSizeDivisor , mMaxTotalEntries / mTotalCacheSizeDivisor );
923+
924+ if (!applyLRU (mMaxTotalSize / mTotalCacheSizeDivisor ,
925+ mMaxTotalEntries / mTotalCacheSizeDivisor )) {
840926 ALOGE (" Error when clearing multifile shader cache" );
841927 return ;
842928 }
@@ -878,6 +964,14 @@ void MultifileBlobCache::processTask(DeferredTask& task) {
878964 return ;
879965 }
880966
967+ if (flags::multifile_blobcache_advanced_usage ()) {
968+ // Update last access time and last modify time
969+ struct timespec times[2 ];
970+ times[0 ].tv_nsec = UTIME_NOW;
971+ times[1 ].tv_nsec = UTIME_NOW;
972+ futimens (fd, times);
973+ }
974+
881975 ALOGV (" DEFERRED: Completed write for: %s" , fullPath.c_str ());
882976 close (fd);
883977
0 commit comments