xref: /aosp_15_r20/frameworks/native/opengl/libs/EGL/MultifileBlobCache.h (revision 38e8c45f13ce32b0dcecb25141ffecaf386fa17f)
1 /*
2  ** Copyright 2022, The Android Open Source Project
3  **
4  ** Licensed under the Apache License, Version 2.0 (the "License");
5  ** you may not use this file except in compliance with the License.
6  ** You may obtain a copy of the License at
7  **
8  **     http://www.apache.org/licenses/LICENSE-2.0
9  **
10  ** Unless required by applicable law or agreed to in writing, software
11  ** distributed under the License is distributed on an "AS IS" BASIS,
12  ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  ** See the License for the specific language governing permissions and
14  ** limitations under the License.
15  */
16 
17 #ifndef ANDROID_MULTIFILE_BLOB_CACHE_H
18 #define ANDROID_MULTIFILE_BLOB_CACHE_H
19 
20 #include <EGL/egl.h>
21 #include <EGL/eglext.h>
22 
23 #include <android-base/thread_annotations.h>
24 #include <cutils/properties.h>
25 #include <future>
26 #include <map>
27 #include <queue>
28 #include <string>
29 #include <thread>
30 #include <unordered_map>
31 #include <unordered_set>
32 
33 #include "FileBlobCache.h"
34 
35 #include <com_android_graphics_egl_flags.h>
36 
37 using namespace com::android::graphics::egl;
38 
39 namespace android {
40 
41 constexpr uint32_t kMultifileBlobCacheVersion = 2;
42 constexpr char kMultifileBlobCacheStatusFile[] = "cache.status";
43 
44 struct MultifileHeader {
45     uint32_t magic;
46     uint32_t crc;
47     EGLsizeiANDROID keySize;
48     EGLsizeiANDROID valueSize;
49 };
50 
51 struct MultifileEntryStats {
52     uint32_t entryHash;
53     EGLsizeiANDROID valueSize;
54     size_t fileSize;
55 };
56 
57 struct MultifileStatus {
58     uint32_t magic;
59     uint32_t crc;
60     uint32_t cacheVersion;
61     char buildId[PROP_VALUE_MAX];
62 };
63 
64 struct MultifileHotCache {
65     int entryFd;
66     uint8_t* entryBuffer;
67     size_t entrySize;
68 };
69 
70 enum class TaskCommand {
71     Invalid = 0,
72     WriteToDisk,
73     Exit,
74 };
75 
76 class DeferredTask {
77 public:
DeferredTask(TaskCommand command)78     DeferredTask(TaskCommand command)
79           : mCommand(command), mEntryHash(0), mBuffer(nullptr), mBufferSize(0) {}
80 
getTaskCommand()81     TaskCommand getTaskCommand() { return mCommand; }
82 
initWriteToDisk(uint32_t entryHash,std::string fullPath,uint8_t * buffer,size_t bufferSize)83     void initWriteToDisk(uint32_t entryHash, std::string fullPath, uint8_t* buffer,
84                          size_t bufferSize) {
85         mCommand = TaskCommand::WriteToDisk;
86         mEntryHash = entryHash;
87         mFullPath = std::move(fullPath);
88         mBuffer = buffer;
89         mBufferSize = bufferSize;
90     }
91 
getEntryHash()92     uint32_t getEntryHash() { return mEntryHash; }
getFullPath()93     std::string& getFullPath() { return mFullPath; }
getBuffer()94     uint8_t* getBuffer() { return mBuffer; }
getBufferSize()95     size_t getBufferSize() { return mBufferSize; };
96 
97 private:
98     TaskCommand mCommand;
99 
100     // Parameters for WriteToDisk
101     uint32_t mEntryHash;
102     std::string mFullPath;
103     uint8_t* mBuffer;
104     size_t mBufferSize;
105 };
106 
107 #if COM_ANDROID_GRAPHICS_EGL_FLAGS(MULTIFILE_BLOBCACHE_ADVANCED_USAGE)
108 struct MultifileTimeLess {
operatorMultifileTimeLess109     bool operator()(const struct timespec& t1, const struct timespec& t2) const {
110         if (t1.tv_sec == t2.tv_sec) {
111             // If seconds are equal, check nanoseconds
112             return t1.tv_nsec < t2.tv_nsec;
113         } else {
114             // Otherwise, compare seconds
115             return t1.tv_sec < t2.tv_sec;
116         }
117     }
118 };
119 
120 // The third parameter here causes all entries to be sorted by access time,
121 // so oldest will be accessed first in applyLRU
122 using MultifileEntryStatsMap =
123         std::multimap<struct timespec, MultifileEntryStats, MultifileTimeLess>;
124 using MultifileEntryStatsMapIter = MultifileEntryStatsMap::iterator;
125 #endif // COM_ANDROID_GRAPHICS_EGL_FLAGS(MULTIFILE_BLOBCACHE_ADVANCED_USAGE)
126 
127 class MultifileBlobCache {
128 public:
129     MultifileBlobCache(size_t maxKeySize, size_t maxValueSize, size_t maxTotalSize,
130                        size_t maxTotalEntries, const std::string& baseDir);
131     ~MultifileBlobCache();
132 
133     void set(const void* key, EGLsizeiANDROID keySize, const void* value,
134              EGLsizeiANDROID valueSize);
135     EGLsizeiANDROID get(const void* key, EGLsizeiANDROID keySize, void* value,
136                         EGLsizeiANDROID valueSize);
137 
138     void finish();
139 
getTotalSize()140     size_t getTotalSize() const { return mTotalCacheSize; }
getTotalEntries()141     size_t getTotalEntries() const { return mTotalCacheEntries; }
getTotalCacheSizeDivisor()142     size_t getTotalCacheSizeDivisor() const { return mTotalCacheSizeDivisor; }
143 
getCurrentBuildId()144     const std::string& getCurrentBuildId() const { return mBuildId; }
setCurrentBuildId(const std::string & buildId)145     void setCurrentBuildId(const std::string& buildId) { mBuildId = buildId; }
146 
getCurrentCacheVersion()147     uint32_t getCurrentCacheVersion() const { return mCacheVersion; }
setCurrentCacheVersion(uint32_t cacheVersion)148     void setCurrentCacheVersion(uint32_t cacheVersion) { mCacheVersion = cacheVersion; }
149 
150 private:
151     void trackEntry(uint32_t entryHash, EGLsizeiANDROID valueSize, size_t fileSize,
152                     const timespec& accessTime);
153     bool contains(uint32_t entryHash) const;
154     bool removeEntry(uint32_t entryHash);
155     MultifileEntryStats getEntryStats(uint32_t entryHash);
156     void updateEntryTime(uint32_t entryHash, const timespec& newTime);
157 
158     bool createStatus(const std::string& baseDir);
159     bool checkStatus(const std::string& baseDir);
160 
161     size_t getFileSize(uint32_t entryHash);
162     size_t getValueSize(uint32_t entryHash);
163 
164     void increaseTotalCacheSize(size_t fileSize);
165     void decreaseTotalCacheSize(size_t fileSize);
166 
167     bool addToHotCache(uint32_t entryHash, int fd, uint8_t* entryBufer, size_t entrySize);
168     bool removeFromHotCache(uint32_t entryHash);
169 
170     bool clearCache();
171     void trimCache();
172     bool applyLRU(size_t cacheSizeLimit, size_t cacheEntryLimit);
173 
174     bool mInitialized;
175     std::string mMultifileDirName;
176 
177     std::string mBuildId;
178     uint32_t mCacheVersion;
179 
180 #if COM_ANDROID_GRAPHICS_EGL_FLAGS(MULTIFILE_BLOBCACHE_ADVANCED_USAGE)
181     std::unordered_map<uint32_t, MultifileEntryStatsMapIter> mEntries;
182     MultifileEntryStatsMap mEntryStats;
183 #else
184     std::unordered_set<uint32_t> mEntries;
185     std::unordered_map<uint32_t, MultifileEntryStats> mEntryStats;
186 #endif // COM_ANDROID_GRAPHICS_EGL_FLAGS(MULTIFILE_BLOBCACHE_ADVANCED_USAGE)
187 
188     std::unordered_map<uint32_t, MultifileHotCache> mHotCache;
189 
190     size_t mMaxKeySize;
191     size_t mMaxValueSize;
192     size_t mMaxTotalSize;
193     size_t mMaxTotalEntries;
194     size_t mTotalCacheSize;
195     size_t mTotalCacheEntries;
196     size_t mTotalCacheSizeDivisor;
197     size_t mHotCacheLimit;
198     size_t mHotCacheEntryLimit;
199     size_t mHotCacheSize;
200 
201     // Below are the components used for deferred writes
202 
203     // Track whether we have pending writes for an entry
204     std::mutex mDeferredWriteStatusMutex;
205     std::multimap<uint32_t, uint8_t*> mDeferredWrites GUARDED_BY(mDeferredWriteStatusMutex);
206 
207     // Functions to work through tasks in the queue
208     void processTasks();
209     void processTasksImpl(bool* exitThread);
210     void processTask(DeferredTask& task);
211 
212     // Used by main thread to create work for the worker thread
213     void queueTask(DeferredTask&& task);
214 
215     // Used by main thread to wait for worker thread to complete all outstanding work.
216     void waitForWorkComplete();
217 
218     std::thread mTaskThread;
219     std::queue<DeferredTask> mTasks;
220     std::mutex mWorkerMutex;
221 
222     // This condition will block the worker thread until a task is queued
223     std::condition_variable mWorkAvailableCondition;
224 
225     // This condition will block the main thread while the worker thread still has tasks
226     std::condition_variable mWorkerIdleCondition;
227 
228     // This bool will track whether all tasks have been completed
229     bool mWorkerThreadIdle;
230 };
231 
232 }; // namespace android
233 
234 #endif // ANDROID_MULTIFILE_BLOB_CACHE_H
235