summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Meeks <michael.meeks@collabora.com>2020-01-02 14:12:27 +0000
committerMichael Meeks <michael.meeks@collabora.com>2020-01-03 12:30:33 +0100
commit42ccf3f85f0089ab823d46e3593a00a6dc2702e6 (patch)
treec146af0a52c918b0d53876c79210b3465eedccec
parentceec2dbcb3f429672a6360e4e71685e58b20640c (diff)
android: file-cache to improve performance.
The transition to java - interestingly to free the passed buffer was showing on profiles. Change-Id: Id1f4f6e60896c3f42fcbf761e535b68318e0a0a2 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/86164 Reviewed-by: Michael Meeks <michael.meeks@collabora.com> Tested-by: Michael Meeks <michael.meeks@collabora.com>
-rw-r--r--sal/osl/unx/file.cxx163
1 files changed, 98 insertions, 65 deletions
diff --git a/sal/osl/unx/file.cxx b/sal/osl/unx/file.cxx
index 576b9bbcf89c..9e3a1c7b272f 100644
--- a/sal/osl/unx/file.cxx
+++ b/sal/osl/unx/file.cxx
@@ -36,6 +36,7 @@
#include "unixerrnostring.hxx"
#include <algorithm>
+#include <vector>
#include <cassert>
#include <limits>
@@ -91,6 +92,9 @@ struct FileHandle_Impl
size_t m_bufsiz;
sal_uInt8 * m_buffer;
+#ifdef ANDROID
+ rtl_String* m_memstreambuf; /*< used for in-memory streams */
+#endif
explicit FileHandle_Impl(int fd, Kind kind = KIND_FD, char const * path = "<anon>");
~FileHandle_Impl();
@@ -782,13 +786,25 @@ static bool osl_file_queryLocking(sal_uInt32 uFlags)
return false;
}
+#ifdef HAVE_O_EXLOCK
+#define OPEN_WRITE_FLAGS ( O_RDWR | O_EXLOCK | O_NONBLOCK )
+#define OPEN_CREATE_FLAGS ( O_CREAT | O_RDWR | O_EXLOCK | O_NONBLOCK )
+#else
+#define OPEN_WRITE_FLAGS ( O_RDWR )
+#define OPEN_CREATE_FLAGS ( O_CREAT | O_RDWR )
+#endif
+
#if defined ANDROID
namespace {
-static oslFileError openMemoryAsFile(void *address, size_t size, oslFileHandle *pHandle,
+static oslFileError openMemoryAsFile(const OString &rData,
+ oslFileHandle *pHandle,
const char *path)
{
+ const char *address = rData.getStr();
+ size_t size = rData.getLength();
+
FileHandle_Impl *pImpl = new FileHandle_Impl(-1, FileHandle_Impl::KIND_MEM, path);
pImpl->m_size = sal::static_int_cast< sal_uInt64 >(size);
@@ -796,49 +812,71 @@ static oslFileError openMemoryAsFile(void *address, size_t size, oslFileHandle *
pImpl->m_bufptr = 0;
pImpl->m_buflen = size;
+ pImpl->m_memstreambuf = rData.pData;
+ rtl_string_acquire(pImpl->m_memstreambuf);
pImpl->m_bufsiz = size;
- pImpl->m_buffer = (sal_uInt8*) address;
+ pImpl->m_buffer = reinterpret_cast<sal_uInt8*>(const_cast<char *>(address));
return osl_File_E_None;
}
-}
-
-#endif
-
-#ifdef HAVE_O_EXLOCK
-#define OPEN_WRITE_FLAGS ( O_RDWR | O_EXLOCK | O_NONBLOCK )
-#define OPEN_CREATE_FLAGS ( O_CREAT | O_RDWR | O_EXLOCK | O_NONBLOCK )
-#else
-#define OPEN_WRITE_FLAGS ( O_RDWR )
-#define OPEN_CREATE_FLAGS ( O_CREAT | O_RDWR )
-#endif
-
/*
- * Reading files from /assets/ on Android is really slow; we should cache
- * small files, particularly sidebar data we need rapidly.
+ * Reading files from /assets/ on Android via a transition into the VM
+ * shows on profiles and is rather slow; so we cache small files as
+ * used by UNO, UI-builder etc.
*/
-#ifdef ANDROID
-struct ACacheEntry {
- OString aFilePath;
- OString aData;
+class AndroidFileCache {
+public:
+ struct Entry {
+ OString maFilePath;
+ OString maData;
+ };
+ AndroidFileCache(size_t nElements)
+ : mnCur(0)
+ {
+ maEntries.resize(nElements);
+ assert (maEntries.size() == nElements);
+ }
+ Entry *find(const char *cpFilePath)
+ {
+ for (auto &it : maEntries)
+ {
+ if (!strcmp(it.maFilePath.getStr(), cpFilePath))
+ return &it;
+ }
+ return nullptr;
+ }
+ // no clever LRU - but - good enough for now.
+ void insert(const char *cpFilePath, OString &rData)
+ {
+ assert (maEntries.size() > 0);
+ if (++mnCur >= maEntries.size())
+ mnCur = 0;
+ maEntries[mnCur].maFilePath = OString(cpFilePath, strlen(cpFilePath));
+ maEntries[mnCur].maData = rData;
+ }
+ static AndroidFileCache &getHitCache()
+ {
+ static AndroidFileCache *pCache = new AndroidFileCache(16);
+ return *pCache;
+ }
+ static AndroidFileCache &getMissCache()
+ {
+ static AndroidFileCache *pCache = new AndroidFileCache(32);
+ return *pCache;
+ }
+private:
+ size_t mnCur;
+ std::vector<Entry> maEntries;
};
-static size_t nHitCacheEntry = 0;
-static ACacheEntry aHitCache[16];
-// static ACacheEntry aMissCache[32];
-ACacheEntry *aCacheFind(ACacheEntry *pCache, int size, const char *cpFilePath)
-{
- for (int i = 0; i < size; ++i)
- if (!strcmp(pCache[i].aFilePath.getStr(), cpFilePath))
- return pCache + i;
- return nullptr;
-}
+} // namespace
+
#endif
-oslFileError openFilePath(const char *cpFilePath, oslFileHandle* pHandle, sal_uInt32 uFlags,
- mode_t mode)
+oslFileError openFilePath(const char *cpFilePath, oslFileHandle* pHandle,
+ sal_uInt32 uFlags, mode_t mode)
{
oslFileError eRet;
@@ -848,51 +886,43 @@ oslFileError openFilePath(const char *cpFilePath, oslFileHandle* pHandle, sal_uI
*/
if (strncmp(cpFilePath, "/assets/", sizeof ("/assets/") - 1) == 0)
{
- void* address;
- size_t size;
- ACacheEntry *pHit;
-
- pHit = aCacheFind(aHitCache, SAL_N_ELEMENTS(aHitCache), cpFilePath);
+ OString aData;
+ bool bCache = true;
+ AndroidFileCache::Entry *pHit = AndroidFileCache::getHitCache().find(cpFilePath);
if (pHit)
- {
- size = pHit->aData.getLength();
- address = malloc(sizeof(char)*size);
- memcpy(address, pHit->aData.getStr(), size);
- }
- // FIXME: make a proper cache class [!]
-/* else if (pHit = aCacheFind(aMissCache, SAL_N_ELEMENTS(aMissCache), cpFilePath))
- {
- address = NULL;
- errno = ENOENT;
- __android_log_print(ANDROID_LOG_ERROR,"libo:sal/osl/unx/file", "failed to open via miss cache %s", cpFilePath);
- return osl_File_E_NOENT;
- } */
+ aData = pHit->maData;
else
{
+ bCache = false;
+ AndroidFileCache::Entry *pMiss = AndroidFileCache::getMissCache().find(cpFilePath);
+ if (pMiss)
+ {
+ errno = ENOENT;
+ __android_log_print(ANDROID_LOG_ERROR,"libo:sal/osl/unx/file", "miss cache: failed to open %s", cpFilePath);
+ return osl_File_E_NOENT;
+ }
AAssetManager* mgr = lo_get_native_assetmgr();
AAsset* asset = AAssetManager_open(mgr, cpFilePath + sizeof("/assets/")-1, AASSET_MODE_BUFFER);
if (!asset)
{
- address = NULL;
+ AndroidFileCache::getMissCache().insert(cpFilePath, aData);
errno = ENOENT;
__android_log_print(ANDROID_LOG_ERROR,"libo:sal/osl/unx/file", "failed to open %s", cpFilePath);
- // FIXME: populate aMissCache[
return osl_File_E_NOENT;
}
else
{
- size = AAsset_getLength(asset);
- address = malloc(sizeof(char)*size);
- AAsset_read(asset,address,size);
+ rtl_String *pData = nullptr;
+ size_t size = AAsset_getLength(asset);
+ rtl_string_new_WithLength(&pData, size);
+ pData->length = size;
+ AAsset_read(asset, pData->buffer, size);
AAsset_close(asset);
- if (size < 50 * 1024)
- {
- size_t nIdx = nHitCacheEntry % SAL_N_ELEMENTS(aHitCache);
- aHitCache[nIdx].aFilePath = OString(cpFilePath, strlen(cpFilePath));
- aHitCache[nIdx].aData = OString((char *)address, size);
- nHitCacheEntry++;
- }
+ aData = OString(pData, SAL_NO_ACQUIRE);
+
+ if (pData->length < 50 * 1024)
+ AndroidFileCache::getHitCache().insert(cpFilePath, aData);
}
}
@@ -903,8 +933,9 @@ oslFileError openFilePath(const char *cpFilePath, oslFileHandle* pHandle, sal_uI
// loading a document from /assets fails with that idiotic
// "General Error" dialog...
}
- SAL_INFO("sal.file", "osl_openFile(" << cpFilePath << ") => " << address);
- return openMemoryAsFile(address, size, pHandle, cpFilePath);
+ SAL_WARN("sal.file", "osl_openFile(" << cpFilePath << ") => " << aData.getLength() <<
+ " bytes from file " << (bCache ? "cache" : "system"));
+ return openMemoryAsFile(aData, pHandle, cpFilePath);
}
#endif
@@ -1099,7 +1130,9 @@ oslFileError SAL_CALL osl_closeFile(oslFileHandle Handle)
if (pImpl->m_kind == FileHandle_Impl::KIND_MEM)
{
#ifdef ANDROID
- free(pImpl->m_buffer);
+ rtl_string_release(pImpl->m_memstreambuf);
+ pImpl->m_memstreambuf = nullptr;
+
pImpl->m_buffer = NULL;
#endif
delete pImpl;