use a different memory allocation strategy for caches

redirect cache related allocations to the same place to attempt to put
them in separate pages from other allocations to release that cache
memory back to OS.

Change-Id: I384658a3d652e668095b69e5a62eae5b972b5857
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/187282
Tested-by: Jenkins
Reviewed-by: Caolán McNamara <caolan.mcnamara@collabora.com>
This commit is contained in:
Caolán McNamara
2025-06-08 19:38:30 +01:00
parent dda0d79370
commit 8f758e7a25
19 changed files with 429 additions and 51 deletions

View File

@ -8,11 +8,14 @@
*
*/
#ifndef INCLUDED_O3TL_LRU_MAP_HXX
#define INCLUDED_O3TL_LRU_MAP_HXX
#pragma once
#include <cassert>
#include <list>
#include <version>
#if defined __cpp_lib_memory_resource
#include <memory_resource>
#endif
#include <unordered_map>
#include <cstddef>
@ -67,11 +70,19 @@ public:
typedef typename std::pair<Key, Value> key_value_pair_t;
private:
#if defined __cpp_lib_memory_resource
typedef std::pmr::list<key_value_pair_t> list_t;
#else
typedef std::list<key_value_pair_t> list_t;
#endif
typedef typename list_t::iterator list_iterator_t;
typedef typename list_t::const_iterator list_const_iterator_t;
#if defined __cpp_lib_memory_resource
typedef std::pmr::unordered_map<Key, list_iterator_t, KeyHash, KeyEqual> map_t;
#else
typedef std::unordered_map<Key, list_iterator_t, KeyHash, KeyEqual> map_t;
#endif
typedef typename map_t::iterator map_iterator_t;
typedef typename map_t::const_iterator map_const_iterator_t;
@ -169,13 +180,22 @@ public:
{
assert(mMaxSize > 0);
}
#if defined __cpp_lib_memory_resource
lru_map(size_t nMaxSize, std::pmr::memory_resource* r)
: mLruList(r)
, mLruMap(r)
, mMaxSize(nMaxSize)
{
assert(mMaxSize > 0);
}
#endif
~lru_map()
{
clearSize();
// Some code .e.g. SalBitmap likes to remove itself from a cache during it's destructor, which means we
// get calls into lru_map while we are in destruction, so use the swap-and-clear idiom to avoid those problems.
mLruMap.clear();
list_t().swap(mLruList);
list_t(mLruList.get_allocator()).swap(mLruList);
}
void setMaxSize(size_t nMaxSize)
@ -286,12 +306,10 @@ public:
void clear()
{
clearSize();
mLruMap.clear();
mLruList.clear();
map_t(mLruMap.get_allocator()).swap(mLruMap);
list_t(mLruList.get_allocator()).swap(mLruList);
}
};
}
#endif /* INCLUDED_O3TL_LRU_MAP_HXX */
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

View File

@ -8,6 +8,7 @@
*/
#pragma once
#include <bit>
#include <stdexcept>
#include <o3tl/concepts.hxx>
@ -40,6 +41,12 @@ constexpr T convertToHex(U cHigh, U cLow)
return (o3tl::convertToHex<T>(cHigh) << 4) | o3tl::convertToHex<T>(cLow);
}
template <o3tl::integral T>
constexpr unsigned int number_of_bits(T x)
{
return sizeof(T) * 8 - std::countl_zero(x);
}
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

View File

@ -10,6 +10,11 @@
#pragma once
#include <vcl/dllapi.h>
#include <rtl/ustring.hxx>
#include <version>
#if defined __cpp_lib_memory_resource
#include <memory_resource>
#endif
#if defined(__COVERITY__)
#define THREAD_UNSAFE_DUMP_BEGIN \
@ -33,8 +38,13 @@ protected:
virtual ~CacheOwner();
public:
virtual void dropCaches() = 0;
// returns true if cache no longer uses GetMemoryResource
virtual bool dropCaches() = 0;
virtual void dumpState(rtl::OStringBuffer& rState) = 0;
virtual OUString getCacheName() const = 0;
#if defined __cpp_lib_memory_resource
static std::pmr::memory_resource& GetMemoryResource();
#endif
};
/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */

View File

@ -69,7 +69,11 @@ public:
static SalLayoutGlyphsCache* self();
SalLayoutGlyphsCache(int size) // needs to be public for tools::DeleteOnDeinit
#if defined __cpp_lib_memory_resource
: mCachedGlyphs(size, &GetMemoryResource())
#else
: mCachedGlyphs(size)
#endif
{
}
@ -96,7 +100,8 @@ public:
};
private:
virtual void dropCaches() override;
virtual OUString getCacheName() const override;
virtual bool dropCaches() override;
virtual void dumpState(rtl::OStringBuffer& rState) override;
struct CachedGlyphsHash

View File

@ -232,10 +232,16 @@ struct PropertySetInfoCache : public CacheOwner
}
private:
virtual void dropCaches() override
virtual OUString getCacheName() const override
{
return "PropertySetInfoCache";
}
virtual bool dropCaches() override
{
std::unique_lock l(gCacheMutex);
gCacheMap.clear();
map_t(gCacheMap.get_allocator()).swap(gCacheMap);
return true;
}
virtual void dumpState(rtl::OStringBuffer& rState) override
@ -247,7 +253,8 @@ private:
}
std::mutex gCacheMutex;
std::unordered_map<uno::Reference<beans::XPropertySetInfo>, uno::Reference<beans::XPropertySetInfo>> gCacheMap;
typedef std::unordered_map<uno::Reference<beans::XPropertySetInfo>, uno::Reference<beans::XPropertySetInfo>> map_t;
map_t gCacheMap;
};
}

View File

@ -85,15 +85,26 @@ class SpellCheckContext::SpellCheckCache : public CacheOwner
}
};
#if defined __cpp_lib_memory_resource
typedef std::pmr::unordered_map<CellPos, std::unique_ptr<MisspellRangesVec>, CellPos::Hash> CellMapType;
typedef std::pmr::unordered_map<LangSharedString, std::unique_ptr<MisspellRangesVec>, LangSharedString::Hash> SharedStringMapType;
#else
typedef std::unordered_map<CellPos, std::unique_ptr<MisspellRangesVec>, CellPos::Hash> CellMapType;
typedef std::unordered_map<LangSharedString, std::unique_ptr<MisspellRangesVec>, LangSharedString::Hash> SharedStringMapType;
#endif
SharedStringMapType maStringMisspells;
CellMapType maEditTextMisspells;
virtual void dropCaches() override
virtual OUString getCacheName() const override
{
return "SpellCheckCache";
}
virtual bool dropCaches() override
{
clear();
return true;
}
virtual void dumpState(rtl::OStringBuffer& rState) override
@ -108,6 +119,10 @@ class SpellCheckContext::SpellCheckCache : public CacheOwner
public:
SpellCheckCache()
#if defined __cpp_lib_memory_resource
: maStringMisspells(&CacheOwner::GetMemoryResource())
, maEditTextMisspells(&CacheOwner::GetMemoryResource())
#endif
{
}
@ -153,8 +168,8 @@ public:
void clear()
{
maStringMisspells.clear();
maEditTextMisspells.clear();
SharedStringMapType(maStringMisspells.get_allocator()).swap(maStringMisspells);
CellMapType(maEditTextMisspells.get_allocator()).swap(maEditTextMisspells);
}
void clearEditTextMap()

View File

@ -58,7 +58,7 @@
#include <svx/unopage.hxx>
#include <comphelper/threadpool.hxx>
#include <atomic>
#include <deque>
#include <vector>
#include <libxml/xmlwriter.h>
#include <osl/diagnose.h>
#include <flyfrm.hxx>
@ -74,7 +74,12 @@ class SwOLELRUCache
, public CacheOwner
{
private:
std::deque<SwOLEObj *> m_OleObjects;
#if defined __cpp_lib_memory_resource
typedef std::pmr::vector<SwOLEObj*> vector_t;
#else
typedef std::vector<SwOLEObj*> vector_t;
#endif
vector_t m_OleObjects;
sal_Int32 m_nLRU_InitSize;
static uno::Sequence< OUString > GetPropertyNames();
@ -82,9 +87,15 @@ private:
void tryShrinkCacheTo(sal_Int32 nVal);
virtual void dropCaches() override
virtual OUString getCacheName() const override
{
return "SwOLELRUCache";
}
virtual bool dropCaches() override
{
tryShrinkCacheTo(0);
return m_OleObjects.empty();
}
virtual void dumpState(rtl::OStringBuffer& rState) override
@ -1299,6 +1310,9 @@ void SwOLEObj::dumpAsXml(xmlTextWriterPtr pWriter) const
SwOLELRUCache::SwOLELRUCache()
: utl::ConfigItem(u"Office.Common/Cache"_ustr)
#if defined __cpp_lib_memory_resource
, m_OleObjects(&GetMemoryResource())
#endif
, m_nLRU_InitSize( 20 )
{
EnableNotification( GetPropertyNames() );
@ -1378,7 +1392,7 @@ void SwOLELRUCache::InsertObj( SwOLEObj& rObj )
if ( pObj->UnloadObject() )
nCount--;
}
m_OleObjects.push_front(&rObj);
m_OleObjects.insert(m_OleObjects.begin(), &rObj);
}
void SwOLELRUCache::RemoveObj( SwOLEObj& rObj )

View File

@ -467,6 +467,7 @@ $(eval $(call gb_Library_add_exception_objects,vcl,\
vcl/source/app/sound \
vcl/source/app/stdtext \
vcl/source/app/svapp \
vcl/source/app/svcache \
vcl/source/app/svdata \
vcl/source/app/svmain \
vcl/source/app/timer \

View File

@ -24,9 +24,11 @@
#include <o3tl/hash_combine.hxx>
#include <vcl/dllapi.h>
#include <vcl/dropcache.hxx>
#include <unicode/uscript.h>
#include <new>
#include <vector>
namespace vcl::text
@ -47,7 +49,11 @@ struct Run
class VCL_DLLPUBLIC TextLayoutCache
{
public:
#if defined __cpp_lib_memory_resource
std::pmr::vector<vcl::text::Run> runs;
#else
std::vector<vcl::text::Run> runs;
#endif
TextLayoutCache(sal_Unicode const* pStr, sal_Int32 const nEnd);
// Creates a cached instance.
static std::shared_ptr<const vcl::text::TextLayoutCache> Create(OUString const&);

View File

@ -56,7 +56,8 @@ public:
void checkStartReduceTimer();
void reduceMemory(std::unique_lock<std::mutex>& rGuard, bool bDropAll = false);
void loopAndReduceMemory(std::unique_lock<std::mutex>& rGuard, bool bDropAll = false);
virtual void dropCaches() override;
virtual OUString getCacheName() const override;
virtual bool dropCaches() override;
virtual void dumpState(rtl::OStringBuffer& rState) override;
};

52
vcl/inc/svcache.hxx Normal file
View File

@ -0,0 +1,52 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include <rtl/alloc.h>
#include <o3tl/numeric.hxx>
#include <array>
#include <map>
#include <version>
#if defined __cpp_lib_memory_resource
#include <memory_resource>
#endif
#if defined __cpp_lib_memory_resource
constexpr unsigned int nAlignments = o3tl::number_of_bits(alignof(std::max_align_t));
class CacheMemory : public std::pmr::memory_resource
{
public:
CacheMemory();
~CacheMemory();
static CacheMemory& GetMemoryResource();
size_t GetAllocatedPages() const;
private:
std::array<rtl_arena_type*, nAlignments> maCacheArenas;
size_t mnSmallest;
size_t mnLargest;
size_t mnPageSize;
size_t mnAllocatedPages;
size_t mnMaxAllocatedPages;
static void* allocPages(rtl_arena_type* arena, sal_Size* size);
static void freePages(rtl_arena_type* arena, void* address, sal_Size size);
virtual void* do_allocate(std::size_t bytes, std::size_t alignment) override;
virtual void do_deallocate(void* p, std::size_t bytes, std::size_t alignment) override;
virtual bool do_is_equal(const std::pmr::memory_resource& other) const noexcept override;
};
#endif
/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */

174
vcl/source/app/svcache.cxx Normal file
View File

@ -0,0 +1,174 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* This file incorporates work covered by the following license notice:
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed
* with this work for additional information regarding copyright
* ownership. The ASF licenses this file to you 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 .
*/
#include <vcl/dropcache.hxx>
#include <svcache.hxx>
#include <svdata.hxx>
#if defined SAL_UNX
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/mman.h>
#elif defined _WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#else
#error Unsupported platform
#endif
CacheOwner::CacheOwner()
{
if (ImplSVData* pSVData = ImplGetSVData())
{
pSVData->registerCacheOwner(*this);
return;
}
SAL_WARN("vcl.app", "Cache owner ctor before ImplSVData created. This is useless.");
}
CacheOwner::~CacheOwner()
{
if (ImplSVData* pSVData = ImplGetSVData())
pSVData->deregisterCacheOwner(*this);
}
#if defined __cpp_lib_memory_resource
#define MEMORY_ALIGN(value, align) (((value) + ((align)-1)) & ~((align)-1))
void* CacheMemory::allocPages(rtl_arena_type* arena, sal_Size* size)
{
CacheMemory* pCacheMemory = reinterpret_cast<CacheMemory*>(arena);
std::size_t n = MEMORY_ALIGN(*size, pCacheMemory->mnPageSize);
void* p;
#if defined SAL_UNX
p = mmap(nullptr, n, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
if (p == MAP_FAILED)
p = nullptr;
#elif defined _WIN32
p = VirtualAlloc(nullptr, n, MEM_COMMIT, PAGE_READWRITE);
#endif
if (p != nullptr)
{
pCacheMemory->mnAllocatedPages += (n / pCacheMemory->mnPageSize);
pCacheMemory->mnMaxAllocatedPages
= std::max(pCacheMemory->mnMaxAllocatedPages, pCacheMemory->mnAllocatedPages);
*size = n;
}
return p;
}
void CacheMemory::freePages(rtl_arena_type* arena, void* address, sal_Size size)
{
CacheMemory* pCacheMemory = reinterpret_cast<CacheMemory*>(arena);
#if defined SAL_UNX
munmap(address, size);
#elif defined _WIN32
(void)size; // unused
VirtualFree(address, 0, MEM_RELEASE);
#endif
pCacheMemory->mnAllocatedPages -= (size / pCacheMemory->mnPageSize);
}
CacheMemory::CacheMemory()
: maCacheArenas{ nullptr }
, mnSmallest(SAL_MAX_SIZE)
, mnLargest(0)
, mnAllocatedPages(0)
, mnMaxAllocatedPages(0)
{
#if defined SAL_UNX
#if defined FREEBSD || defined NETBSD || defined OPENBSD || defined DRAGONFLY || defined HAIKU
mnPageSize = getpagesize();
#else
// coverity[ tainted_data_return : FALSE ] version 2023.12.2
mnPageSize = sysconf(_SC_PAGESIZE);
#endif
#elif defined _WIN32
SYSTEM_INFO info;
GetSystemInfo(&info);
mnPageSize = info.dwPageSize;
#else
#error Unsupported platform
#endif
}
size_t CacheMemory::GetAllocatedPages() const { return mnAllocatedPages; }
CacheMemory::~CacheMemory()
{
SAL_INFO("vcl", "cachememory, smallest/largest are: "
<< mnSmallest << ", " << mnLargest << "total pages allocated: "
<< mnMaxAllocatedPages << ", current allocated pages" << mnAllocatedPages);
for (size_t i = 0; i < maCacheArenas.size(); ++i)
{
if (!maCacheArenas[i])
continue;
SAL_INFO("vcl", "cachememory, destroying arena for alignment: " << (1 << i));
rtl_arena_destroy(maCacheArenas[i]);
}
}
void* CacheMemory::do_allocate(std::size_t bytes, std::size_t alignment)
{
alignment = std::max<std::size_t>(alignment, 4);
const unsigned int nSlot = o3tl::number_of_bits(alignment) - 1;
if (!maCacheArenas[nSlot])
{
maCacheArenas[nSlot]
= rtl_arena_create("cache_internal_arena", alignment, 0,
reinterpret_cast<rtl_arena_type*>(this), allocPages, freePages, 0);
}
mnSmallest = std::min(mnSmallest, bytes);
mnLargest = std::max(mnLargest, bytes);
sal_Size size = MEMORY_ALIGN(bytes, alignment);
return rtl_arena_alloc(maCacheArenas[nSlot], &size);
}
void CacheMemory::do_deallocate(void* p, std::size_t bytes, std::size_t alignment)
{
alignment = std::max<std::size_t>(alignment, 4);
const unsigned int nSlot = o3tl::number_of_bits(alignment) - 1;
sal_Size size = MEMORY_ALIGN(bytes, alignment);
rtl_arena_free(maCacheArenas[nSlot], p, size);
}
bool CacheMemory::do_is_equal(const std::pmr::memory_resource& other) const noexcept
{
SAL_WARN("vcl", "CacheMemory::do_is_equal called");
return &other == this;
}
//static
CacheMemory& CacheMemory::GetMemoryResource()
{
static CacheMemory aCacheMemory;
return aCacheMemory;
}
//static
std::pmr::memory_resource& CacheOwner::GetMemoryResource()
{
return CacheMemory::GetMemoryResource();
}
#endif
/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */

View File

@ -45,6 +45,7 @@
#include <vcl/toolkit/dialog.hxx>
#include <salinst.hxx>
#include <salgdi.hxx>
#include <svcache.hxx>
#include <svdata.hxx>
#include <salsys.hxx>
#include <windowdev.hxx>
@ -444,24 +445,18 @@ void ImplSVData::dropCaches()
// copy, some caches self-delete on emptying, e.g. SwOLELRUCache
auto aCacheOwners = maCacheOwners;
bool bAllCachesDropped = true;
for (CacheOwner* pCacheOwner : aCacheOwners)
pCacheOwner->dropCaches();
}
CacheOwner::CacheOwner()
{
if (ImplSVData* pSVData = ImplGetSVData())
{
pSVData->registerCacheOwner(*this);
return;
bool bCacheDropped = pCacheOwner->dropCaches();
SAL_WARN_IF(!bCacheDropped, "vcl", "Cache " << pCacheOwner->getCacheName() << " drop failed");
bAllCachesDropped &= bCacheDropped;
}
SAL_WARN("vcl.app", "Cache owner ctor before ImplSVData created. This is useless.");
}
CacheOwner::~CacheOwner()
{
if (ImplSVData* pSVData = ImplGetSVData())
pSVData->deregisterCacheOwner(*this);
#if defined __cpp_lib_memory_resource
assert(!bAllCachesDropped || CacheMemory::GetMemoryResource().GetAllocatedPages() == 0);
#endif
(void)bAllCachesDropped;
}
void ImplSVData::dumpState(rtl::OStringBuffer &rState)

View File

@ -590,7 +590,13 @@ size_t SalLayoutGlyphsCache::GlyphsCost::operator()(const SalLayoutGlyphs& glyph
return cost;
}
void SalLayoutGlyphsCache::dropCaches() { clear(); }
OUString SalLayoutGlyphsCache::getCacheName() const { return "SalLayoutGlyphsCache"; }
bool SalLayoutGlyphsCache::dropCaches()
{
clear();
return true;
}
void SalLayoutGlyphsCache::dumpState(rtl::OStringBuffer& rState)
{

View File

@ -119,10 +119,13 @@ void MemoryManager::swappedOut(MemoryManaged* pMemoryManaged, sal_Int64 nNewSize
changeExisting(pMemoryManaged, nNewSize);
}
void MemoryManager::dropCaches()
OUString MemoryManager::getCacheName() const { return "MemoryManager"; }
bool MemoryManager::dropCaches()
{
std::unique_lock aGuard(maMutex);
reduceMemory(aGuard, true);
return true;
}
void MemoryManager::dumpState(rtl::OStringBuffer& rState)

View File

@ -43,7 +43,14 @@
namespace {
struct WavyLineCache final : public CacheOwner
{
WavyLineCache () : m_aItems( 10 ) {}
WavyLineCache()
#if defined __cpp_lib_memory_resource
: m_aItems(10, &GetMemoryResource())
#else
: m_aItems(10)
#endif
{
}
bool find( Color aLineColor, size_t nLineWidth, size_t nWaveHeight, size_t nWordWidth, BitmapEx& rOutput )
{
@ -67,9 +74,12 @@ namespace {
rOutput = aBitmap;
}
virtual void dropCaches() override
virtual OUString getCacheName() const override { return "WavyLineCache"; }
virtual bool dropCaches() override
{
m_aItems.clear();
return true;
}
virtual void dumpState(rtl::OStringBuffer& rState) override

View File

@ -29,9 +29,14 @@
#include <officecfg/Office/Common.hxx>
#include <vcl/dropcache.hxx>
#include <memory>
namespace vcl::text
{
TextLayoutCache::TextLayoutCache(sal_Unicode const* pStr, sal_Int32 const nEnd)
#if defined __cpp_lib_memory_resource
: runs(&CacheOwner::GetMemoryResource())
#endif
{
vcl::ScriptRun aScriptRun(reinterpret_cast<const UChar*>(pStr), nEnd);
while (aScriptRun.next())
@ -57,10 +62,18 @@ struct TextLayoutCacheMap : public CacheOwner
FastStringCompareEqual, TextLayoutCacheCost>
Cache;
#if defined __cpp_lib_memory_resource
std::pmr::polymorphic_allocator<TextLayoutCache> allocator;
#endif
Cache cache;
TextLayoutCacheMap(int capacity)
#if defined __cpp_lib_memory_resource
: allocator(&CacheOwner::GetMemoryResource())
, cache(capacity, &CacheOwner::GetMemoryResource())
#else
: cache(capacity)
#endif
{
}
@ -69,12 +82,23 @@ struct TextLayoutCacheMap : public CacheOwner
auto it = cache.find(rString);
if (it != cache.end())
return it->second;
auto ret = std::make_shared<const TextLayoutCache>(rString.getStr(), rString.getLength());
#if defined __cpp_lib_memory_resource
auto ret = std::allocate_shared<TextLayoutCache>(allocator, rString.getStr(),
rString.getLength());
#else
auto ret = std::make_shared<TextLayoutCache>(rString.getStr(), rString.getLength());
#endif
cache.insert({ rString, ret });
return ret;
}
virtual void dropCaches() override { cache.clear(); }
virtual OUString getCacheName() const override { return "TextLayoutCache"; }
virtual bool dropCaches() override
{
cache.clear();
return true;
}
virtual void dumpState(rtl::OStringBuffer& rState) override
{
@ -100,7 +124,7 @@ std::shared_ptr<const TextLayoutCache> TextLayoutCache::Create(OUString const& r
: 100);
if (TextLayoutCacheMap* map = cache.get())
return map->Create(rString);
return std::make_shared<const TextLayoutCache>(rString.getStr(), rString.getLength());
return std::make_shared<TextLayoutCache>(rString.getStr(), rString.getLength());
}
}

View File

@ -121,7 +121,12 @@ private:
public:
CachedFontConfigFontOptions()
: lru_options_cache(10) // arbitrary cache size of 10
// arbitrary cache size of 10
#if defined __cpp_lib_memory_resource
: lru_options_cache(10, &CacheOwner::GetMemoryResource())
#else
: lru_options_cache(10)
#endif
{
}
@ -139,9 +144,15 @@ public:
}
private:
virtual void dropCaches() override
virtual OUString getCacheName() const override
{
return "CachedFontConfigFontOptions";
}
virtual bool dropCaches() override
{
lru_options_cache.clear();
return true;
}
virtual void dumpState(rtl::OStringBuffer& rState) override

View File

@ -62,12 +62,22 @@ public:
};
private:
typedef std::deque< std::pair<cairo_font_face_t*, CacheId> > LRUFonts;
#if defined __cpp_lib_memory_resource
typedef std::pmr::vector< std::pair<cairo_font_face_t*, CacheId> > LRUFonts;
#else
typedef std::vector< std::pair<cairo_font_face_t*, CacheId> > LRUFonts;
#endif
LRUFonts maLRUFonts;
virtual void dropCaches() override
virtual OUString getCacheName() const override
{
maLRUFonts.clear();
return "CairoFontsCache";
}
virtual bool dropCaches() override
{
LRUFonts(maLRUFonts.get_allocator()).swap(maLRUFonts);
return true;
}
virtual void dumpState(rtl::OStringBuffer& rState) override
@ -77,6 +87,15 @@ private:
}
public:
CairoFontsCache()
#if defined __cpp_lib_memory_resource
: maLRUFonts(&CacheOwner::GetMemoryResource())
#else
: maLRUFonts()
#endif
{
}
void CacheFont(cairo_font_face_t* pFont, const CacheId &rId);
cairo_font_face_t* FindCachedFont(const CacheId &rId);
};
@ -89,19 +108,19 @@ CairoFontsCache& getCairoFontsCache()
void CairoFontsCache::CacheFont(cairo_font_face_t* pFont, const CairoFontsCache::CacheId &rId)
{
maLRUFonts.push_front( std::pair<cairo_font_face_t*, CairoFontsCache::CacheId>(pFont, rId) );
maLRUFonts.push_back( std::pair<cairo_font_face_t*, CairoFontsCache::CacheId>(pFont, rId) );
if (maLRUFonts.size() > 8)
{
cairo_font_face_destroy(maLRUFonts.back().first);
maLRUFonts.pop_back();
cairo_font_face_destroy(maLRUFonts.front().first);
maLRUFonts.erase(maLRUFonts.begin());
}
}
cairo_font_face_t* CairoFontsCache::FindCachedFont(const CairoFontsCache::CacheId &rId)
{
auto aI = std::find_if(maLRUFonts.begin(), maLRUFonts.end(),
auto aI = std::find_if(maLRUFonts.rbegin(), maLRUFonts.rend(),
[&rId](const LRUFonts::value_type& rFont) { return rFont.second == rId; });
if (aI != maLRUFonts.end())
if (aI != maLRUFonts.rend())
return aI->first;
return nullptr;
}