diff options
author | 2017-10-09 15:56:10 -0400 | |
---|---|---|
committer | 2017-11-08 18:55:16 +0000 | |
commit | 9e7cd07a30a0ed27852ad04d2997f00387b55dcf (patch) | |
tree | dc44cd72baa5adf4feb5234d6c32aa2d32529360 | |
parent | e36e7be0fe446320fe86b0825f902439fdd1bda7 (diff) |
Move some of the logic from egl_cache_t into FileBlobCache
HWUI is using BlobCache to implement SkSL shader cache very
similar to egl_cache_t. Create a new class FileBlobCache,
that is used by both egl_cache_t and HWUI. FileBlobCache adds
the logic to save and load the BlobCache from a memory mapped
file.
Test: Built and ran Android. Verified that EGL cache still works
Test: for gmail and calc apps.
Bug: 66740665
Change-Id: Ia4d194963d039a60244f3bc76108844418adc99d
-rw-r--r-- | opengl/libs/Android.bp | 16 | ||||
-rw-r--r-- | opengl/libs/EGL/BlobCache.cpp | 2 | ||||
-rw-r--r-- | opengl/libs/EGL/BlobCache.h | 15 | ||||
-rw-r--r-- | opengl/libs/EGL/FileBlobCache.cpp | 185 | ||||
-rw-r--r-- | opengl/libs/EGL/FileBlobCache.h | 43 | ||||
-rw-r--r-- | opengl/libs/EGL/egl_cache.cpp | 170 | ||||
-rw-r--r-- | opengl/libs/EGL/egl_cache.h | 12 |
7 files changed, 259 insertions, 184 deletions
diff --git a/opengl/libs/Android.bp b/opengl/libs/Android.bp index 32c2d7e0d5..d43c1648be 100644 --- a/opengl/libs/Android.bp +++ b/opengl/libs/Android.bp @@ -122,6 +122,16 @@ cc_library_static { }, } +cc_library_static { + name: "libEGL_blobCache", + defaults: ["egl_libs_defaults"], + srcs: [ + "EGL/BlobCache.cpp", + "EGL/FileBlobCache.cpp", + ], + export_include_dirs: ["EGL"], +} + cc_library_shared { name: "libEGL", defaults: ["egl_libs_defaults"], @@ -133,7 +143,6 @@ cc_library_shared { "EGL/egl.cpp", "EGL/eglApi.cpp", "EGL/Loader.cpp", - "EGL/BlobCache.cpp", ], shared_libs: [ "libvndksupport", @@ -143,7 +152,10 @@ cc_library_shared { "libhidltransport", "libutils", ], - static_libs: ["libEGL_getProcAddress"], + static_libs: [ + "libEGL_getProcAddress", + "libEGL_blobCache", + ], ldflags: ["-Wl,--exclude-libs=ALL"], export_include_dirs: ["EGL/include"], } diff --git a/opengl/libs/EGL/BlobCache.cpp b/opengl/libs/EGL/BlobCache.cpp index 0624b609ce..b3752f5bcc 100644 --- a/opengl/libs/EGL/BlobCache.cpp +++ b/opengl/libs/EGL/BlobCache.cpp @@ -37,9 +37,9 @@ static const uint32_t blobCacheVersion = 3; static const uint32_t blobCacheDeviceVersion = 1; BlobCache::BlobCache(size_t maxKeySize, size_t maxValueSize, size_t maxTotalSize): + mMaxTotalSize(maxTotalSize), mMaxKeySize(maxKeySize), mMaxValueSize(maxValueSize), - mMaxTotalSize(maxTotalSize), mTotalSize(0) { int64_t now = std::chrono::steady_clock::now().time_since_epoch().count(); #ifdef _WIN32 diff --git a/opengl/libs/EGL/BlobCache.h b/opengl/libs/EGL/BlobCache.h index a0a270a5fe..1f5d5357e6 100644 --- a/opengl/libs/EGL/BlobCache.h +++ b/opengl/libs/EGL/BlobCache.h @@ -97,6 +97,14 @@ public: // int unflatten(void const* buffer, size_t size); +protected: + // mMaxTotalSize is the maximum size that all cache entries can occupy. This + // includes space for both keys and values. When a call to BlobCache::set + // would otherwise cause this limit to be exceeded, either the key/value + // pair passed to BlobCache::set will not be cached or other cache entries + // will be evicted from the cache to make room for the new entry. + const size_t mMaxTotalSize; + private: // Copying is disallowed. BlobCache(const BlobCache&); @@ -220,13 +228,6 @@ private: // simply not add the key/value pair to the cache. const size_t mMaxValueSize; - // mMaxTotalSize is the maximum size that all cache entries can occupy. This - // includes space for both keys and values. When a call to BlobCache::set - // would otherwise cause this limit to be exceeded, either the key/value - // pair passed to BlobCache::set will not be cached or other cache entries - // will be evicted from the cache to make room for the new entry. - const size_t mMaxTotalSize; - // mTotalSize is the total combined size of all keys and values currently in // the cache. size_t mTotalSize; diff --git a/opengl/libs/EGL/FileBlobCache.cpp b/opengl/libs/EGL/FileBlobCache.cpp new file mode 100644 index 0000000000..ff608a38a4 --- /dev/null +++ b/opengl/libs/EGL/FileBlobCache.cpp @@ -0,0 +1,185 @@ +/* + ** Copyright 2017, The Android Open Source Project + ** + ** Licensed under the Apache License, Version 2.0 (the "License"); + ** you may not use this file except in compliance with the License. + ** You may obtain a copy of the License at + ** + ** http://www.apache.org/licenses/LICENSE-2.0 + ** + ** Unless required by applicable law or agreed to in writing, software + ** distributed under the License is distributed on an "AS IS" BASIS, + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ** See the License for the specific language governing permissions and + ** limitations under the License. + */ + +#include "FileBlobCache.h" + +#include <inttypes.h> +#include <log/log.h> +#include <sys/mman.h> +#include <sys/stat.h> + + +// Cache file header +static const char* cacheFileMagic = "EGL$"; +static const size_t cacheFileHeaderSize = 8; + +namespace android { + +static uint32_t crc32c(const uint8_t* buf, size_t len) { + const uint32_t polyBits = 0x82F63B78; + uint32_t r = 0; + for (size_t i = 0; i < len; i++) { + r ^= buf[i]; + for (int j = 0; j < 8; j++) { + if (r & 1) { + r = (r >> 1) ^ polyBits; + } else { + r >>= 1; + } + } + } + return r; +} + +FileBlobCache::FileBlobCache(size_t maxKeySize, size_t maxValueSize, size_t maxTotalSize, + const std::string& filename) + : BlobCache(maxKeySize, maxValueSize, maxTotalSize) + , mFilename(filename) { + if (mFilename.length() > 0) { + size_t headerSize = cacheFileHeaderSize; + + int fd = open(mFilename.c_str(), O_RDONLY, 0); + if (fd == -1) { + if (errno != ENOENT) { + ALOGE("error opening cache file %s: %s (%d)", mFilename.c_str(), + strerror(errno), errno); + } + return; + } + + struct stat statBuf; + if (fstat(fd, &statBuf) == -1) { + ALOGE("error stat'ing cache file: %s (%d)", strerror(errno), errno); + close(fd); + return; + } + + // Sanity check the size before trying to mmap it. + size_t fileSize = statBuf.st_size; + if (fileSize > mMaxTotalSize * 2) { + ALOGE("cache file is too large: %#" PRIx64, + static_cast<off64_t>(statBuf.st_size)); + close(fd); + return; + } + + uint8_t* buf = reinterpret_cast<uint8_t*>(mmap(NULL, fileSize, + PROT_READ, MAP_PRIVATE, fd, 0)); + if (buf == MAP_FAILED) { + ALOGE("error mmaping cache file: %s (%d)", strerror(errno), + errno); + close(fd); + return; + } + + // Check the file magic and CRC + size_t cacheSize = fileSize - headerSize; + if (memcmp(buf, cacheFileMagic, 4) != 0) { + ALOGE("cache file has bad mojo"); + close(fd); + return; + } + uint32_t* crc = reinterpret_cast<uint32_t*>(buf + 4); + if (crc32c(buf + headerSize, cacheSize) != *crc) { + ALOGE("cache file failed CRC check"); + close(fd); + return; + } + + int err = unflatten(buf + headerSize, cacheSize); + if (err < 0) { + ALOGE("error reading cache contents: %s (%d)", strerror(-err), + -err); + munmap(buf, fileSize); + close(fd); + return; + } + + munmap(buf, fileSize); + close(fd); + } +} + +void FileBlobCache::writeToFile() { + if (mFilename.length() > 0) { + size_t cacheSize = getFlattenedSize(); + size_t headerSize = cacheFileHeaderSize; + const char* fname = mFilename.c_str(); + + // Try to create the file with no permissions so we can write it + // without anyone trying to read it. + int fd = open(fname, O_CREAT | O_EXCL | O_RDWR, 0); + if (fd == -1) { + if (errno == EEXIST) { + // The file exists, delete it and try again. + if (unlink(fname) == -1) { + // No point in retrying if the unlink failed. + ALOGE("error unlinking cache file %s: %s (%d)", fname, + strerror(errno), errno); + return; + } + // Retry now that we've unlinked the file. + fd = open(fname, O_CREAT | O_EXCL | O_RDWR, 0); + } + if (fd == -1) { + ALOGE("error creating cache file %s: %s (%d)", fname, + strerror(errno), errno); + return; + } + } + + size_t fileSize = headerSize + cacheSize; + + uint8_t* buf = new uint8_t [fileSize]; + if (!buf) { + ALOGE("error allocating buffer for cache contents: %s (%d)", + strerror(errno), errno); + close(fd); + unlink(fname); + return; + } + + int err = flatten(buf + headerSize, cacheSize); + if (err < 0) { + ALOGE("error writing cache contents: %s (%d)", strerror(-err), + -err); + delete [] buf; + close(fd); + unlink(fname); + return; + } + + // Write the file magic and CRC + memcpy(buf, cacheFileMagic, 4); + uint32_t* crc = reinterpret_cast<uint32_t*>(buf + 4); + *crc = crc32c(buf + headerSize, cacheSize); + + if (write(fd, buf, fileSize) == -1) { + ALOGE("error writing cache file: %s (%d)", strerror(errno), + errno); + delete [] buf; + close(fd); + unlink(fname); + return; + } + + delete [] buf; + fchmod(fd, S_IRUSR); + close(fd); + } +} + +}
\ No newline at end of file diff --git a/opengl/libs/EGL/FileBlobCache.h b/opengl/libs/EGL/FileBlobCache.h new file mode 100644 index 0000000000..393703f234 --- /dev/null +++ b/opengl/libs/EGL/FileBlobCache.h @@ -0,0 +1,43 @@ +/* + ** Copyright 2017, The Android Open Source Project + ** + ** Licensed under the Apache License, Version 2.0 (the "License"); + ** you may not use this file except in compliance with the License. + ** You may obtain a copy of the License at + ** + ** http://www.apache.org/licenses/LICENSE-2.0 + ** + ** Unless required by applicable law or agreed to in writing, software + ** distributed under the License is distributed on an "AS IS" BASIS, + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ** See the License for the specific language governing permissions and + ** limitations under the License. + */ + +#ifndef ANDROID_FILE_BLOB_CACHE_H +#define ANDROID_FILE_BLOB_CACHE_H + +#include "BlobCache.h" +#include <string> + +namespace android { + +class FileBlobCache : public BlobCache { +public: + // FileBlobCache attempts to load the saved cache contents from disk into + // BlobCache. + FileBlobCache(size_t maxKeySize, size_t maxValueSize, size_t maxTotalSize, + const std::string& filename); + + // writeToFile attempts to save the current contents of BlobCache to + // disk. + void writeToFile(); + +private: + // mFilename is the name of the file for storing cache contents. + std::string mFilename; +}; + +} // namespace android + +#endif // ANDROID_BLOB_CACHE_H diff --git a/opengl/libs/EGL/egl_cache.cpp b/opengl/libs/EGL/egl_cache.cpp index 579e422c1a..ec548f3121 100644 --- a/opengl/libs/EGL/egl_cache.cpp +++ b/opengl/libs/EGL/egl_cache.cpp @@ -20,12 +20,8 @@ #include "egl_display.h" - #include <private/EGL/cache.h> -#include <inttypes.h> -#include <sys/mman.h> -#include <sys/stat.h> #include <unistd.h> #include <thread> @@ -37,10 +33,6 @@ static const size_t maxKeySize = 12 * 1024; static const size_t maxValueSize = 64 * 1024; static const size_t maxTotalSize = 2 * 1024 * 1024; -// Cache file header -static const char* cacheFileMagic = "EGL$"; -static const size_t cacheFileHeaderSize = 8; - // The time in seconds to wait before saving newly inserted cache entries. static const unsigned int deferredSaveDelay = 4; @@ -124,7 +116,9 @@ void egl_cache_t::initialize(egl_display_t *display) { void egl_cache_t::terminate() { std::lock_guard<std::mutex> lock(mMutex); - saveBlobCacheLocked(); + if (mBlobCache) { + mBlobCache->writeToFile(); + } mBlobCache = NULL; } @@ -146,8 +140,8 @@ void egl_cache_t::setBlob(const void* key, EGLsizeiANDROID keySize, std::thread deferredSaveThread([this]() { sleep(deferredSaveDelay); std::lock_guard<std::mutex> lock(mMutex); - if (mInitialized) { - saveBlobCacheLocked(); + if (mInitialized && mBlobCache) { + mBlobCache->writeToFile(); } mSavePending = false; }); @@ -179,163 +173,11 @@ void egl_cache_t::setCacheFilename(const char* filename) { BlobCache* egl_cache_t::getBlobCacheLocked() { if (mBlobCache == nullptr) { - mBlobCache.reset(new BlobCache(maxKeySize, maxValueSize, maxTotalSize)); - loadBlobCacheLocked(); + mBlobCache.reset(new FileBlobCache(maxKeySize, maxValueSize, maxTotalSize, mFilename)); } return mBlobCache.get(); } -static uint32_t crc32c(const uint8_t* buf, size_t len) { - const uint32_t polyBits = 0x82F63B78; - uint32_t r = 0; - for (size_t i = 0; i < len; i++) { - r ^= buf[i]; - for (int j = 0; j < 8; j++) { - if (r & 1) { - r = (r >> 1) ^ polyBits; - } else { - r >>= 1; - } - } - } - return r; -} - -void egl_cache_t::saveBlobCacheLocked() { - if (mFilename.length() > 0 && mBlobCache != NULL) { - size_t cacheSize = mBlobCache->getFlattenedSize(); - size_t headerSize = cacheFileHeaderSize; - const char* fname = mFilename.c_str(); - - // Try to create the file with no permissions so we can write it - // without anyone trying to read it. - int fd = open(fname, O_CREAT | O_EXCL | O_RDWR, 0); - if (fd == -1) { - if (errno == EEXIST) { - // The file exists, delete it and try again. - if (unlink(fname) == -1) { - // No point in retrying if the unlink failed. - ALOGE("error unlinking cache file %s: %s (%d)", fname, - strerror(errno), errno); - return; - } - // Retry now that we've unlinked the file. - fd = open(fname, O_CREAT | O_EXCL | O_RDWR, 0); - } - if (fd == -1) { - ALOGE("error creating cache file %s: %s (%d)", fname, - strerror(errno), errno); - return; - } - } - - size_t fileSize = headerSize + cacheSize; - - uint8_t* buf = new uint8_t [fileSize]; - if (!buf) { - ALOGE("error allocating buffer for cache contents: %s (%d)", - strerror(errno), errno); - close(fd); - unlink(fname); - return; - } - - int err = mBlobCache->flatten(buf + headerSize, cacheSize); - if (err < 0) { - ALOGE("error writing cache contents: %s (%d)", strerror(-err), - -err); - delete [] buf; - close(fd); - unlink(fname); - return; - } - - // Write the file magic and CRC - memcpy(buf, cacheFileMagic, 4); - uint32_t* crc = reinterpret_cast<uint32_t*>(buf + 4); - *crc = crc32c(buf + headerSize, cacheSize); - - if (write(fd, buf, fileSize) == -1) { - ALOGE("error writing cache file: %s (%d)", strerror(errno), - errno); - delete [] buf; - close(fd); - unlink(fname); - return; - } - - delete [] buf; - fchmod(fd, S_IRUSR); - close(fd); - } -} - -void egl_cache_t::loadBlobCacheLocked() { - if (mFilename.length() > 0) { - size_t headerSize = cacheFileHeaderSize; - - int fd = open(mFilename.c_str(), O_RDONLY, 0); - if (fd == -1) { - if (errno != ENOENT) { - ALOGE("error opening cache file %s: %s (%d)", mFilename.c_str(), - strerror(errno), errno); - } - return; - } - - struct stat statBuf; - if (fstat(fd, &statBuf) == -1) { - ALOGE("error stat'ing cache file: %s (%d)", strerror(errno), errno); - close(fd); - return; - } - - // Sanity check the size before trying to mmap it. - size_t fileSize = statBuf.st_size; - if (fileSize > maxTotalSize * 2) { - ALOGE("cache file is too large: %#" PRIx64, - static_cast<off64_t>(statBuf.st_size)); - close(fd); - return; - } - - uint8_t* buf = reinterpret_cast<uint8_t*>(mmap(NULL, fileSize, - PROT_READ, MAP_PRIVATE, fd, 0)); - if (buf == MAP_FAILED) { - ALOGE("error mmaping cache file: %s (%d)", strerror(errno), - errno); - close(fd); - return; - } - - // Check the file magic and CRC - size_t cacheSize = fileSize - headerSize; - if (memcmp(buf, cacheFileMagic, 4) != 0) { - ALOGE("cache file has bad mojo"); - close(fd); - return; - } - uint32_t* crc = reinterpret_cast<uint32_t*>(buf + 4); - if (crc32c(buf + headerSize, cacheSize) != *crc) { - ALOGE("cache file failed CRC check"); - close(fd); - return; - } - - int err = mBlobCache->unflatten(buf + headerSize, cacheSize); - if (err < 0) { - ALOGE("error reading cache contents: %s (%d)", strerror(-err), - -err); - munmap(buf, fileSize); - close(fd); - return; - } - - munmap(buf, fileSize); - close(fd); - } -} - // ---------------------------------------------------------------------------- }; // namespace android // ---------------------------------------------------------------------------- diff --git a/opengl/libs/EGL/egl_cache.h b/opengl/libs/EGL/egl_cache.h index 56360f0bc8..7382b913fa 100644 --- a/opengl/libs/EGL/egl_cache.h +++ b/opengl/libs/EGL/egl_cache.h @@ -20,7 +20,7 @@ #include <EGL/egl.h> #include <EGL/eglext.h> -#include "BlobCache.h" +#include "FileBlobCache.h" #include <memory> #include <mutex> @@ -82,14 +82,6 @@ private: // possible. BlobCache* getBlobCacheLocked(); - // saveBlobCache attempts to save the current contents of mBlobCache to - // disk. - void saveBlobCacheLocked(); - - // loadBlobCache attempts to load the saved cache contents from disk into - // mBlobCache. - void loadBlobCacheLocked(); - // mInitialized indicates whether the egl_cache_t is in the initialized // state. It is initialized to false at construction time, and gets set to // true when initialize is called. It is set back to false when terminate @@ -101,7 +93,7 @@ private: // mBlobCache is the cache in which the key/value blob pairs are stored. It // is initially NULL, and will be initialized by getBlobCacheLocked the // first time it's needed. - std::unique_ptr<BlobCache> mBlobCache; + std::unique_ptr<FileBlobCache> mBlobCache; // mFilename is the name of the file for storing cache contents in between // program invocations. It is initialized to an empty string at |