include/o3tl/lru_map.hxx | 32 ++++- include/o3tl/numeric.hxx | 7 + include/vcl/dropcache.hxx | 12 +- include/vcl/glyphitemcache.hxx | 7 + sc/source/ui/unoobj/shapeuno.cxx | 13 +- sc/source/ui/view/spellcheckcontext.cxx | 21 +++ sw/source/core/ole/ndole.cxx | 22 +++ vcl/Library_vcl.mk | 1 vcl/inc/TextLayoutCache.hxx | 6 + vcl/inc/graphic/Manager.hxx | 3 vcl/inc/svcache.hxx | 52 ++++++++ vcl/source/app/svcache.cxx | 174 +++++++++++++++++++++++++++++ vcl/source/app/svdata.cxx | 23 +-- vcl/source/gdi/impglyphitem.cxx | 8 + vcl/source/graphic/Manager.cxx | 5 vcl/source/outdev/textline.cxx | 14 ++ vcl/source/text/TextLayoutCache.cxx | 30 ++++- vcl/unx/generic/fontmanager/fontconfig.cxx | 15 ++ vcl/unx/generic/gdi/cairotextrender.cxx | 35 ++++- 19 files changed, 429 insertions(+), 51 deletions(-)
New commits: commit 8f758e7a251d31c2cc434f9d4efe74b2d4462aa5 Author: Caolán McNamara <caolan.mcnam...@collabora.com> AuthorDate: Sun Jun 8 19:38:30 2025 +0100 Commit: Caolán McNamara <caolan.mcnam...@collabora.com> CommitDate: Thu Jul 10 19:05:48 2025 +0200 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.mcnam...@collabora.com> diff --git a/include/o3tl/lru_map.hxx b/include/o3tl/lru_map.hxx index 447cfcdaac86..65268ea85b4d 100644 --- a/include/o3tl/lru_map.hxx +++ b/include/o3tl/lru_map.hxx @@ -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: */ diff --git a/include/o3tl/numeric.hxx b/include/o3tl/numeric.hxx index 5a6b4b17858b..3736d60b60d1 100644 --- a/include/o3tl/numeric.hxx +++ b/include/o3tl/numeric.hxx @@ -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: */ diff --git a/include/vcl/dropcache.hxx b/include/vcl/dropcache.hxx index 13bf55c99364..414cc906855f 100644 --- a/include/vcl/dropcache.hxx +++ b/include/vcl/dropcache.hxx @@ -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: */ diff --git a/include/vcl/glyphitemcache.hxx b/include/vcl/glyphitemcache.hxx index 92e427fe1aed..f6359639090f 100644 --- a/include/vcl/glyphitemcache.hxx +++ b/include/vcl/glyphitemcache.hxx @@ -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 diff --git a/sc/source/ui/unoobj/shapeuno.cxx b/sc/source/ui/unoobj/shapeuno.cxx index 171eb0a2371f..bc5b09423dde 100644 --- a/sc/source/ui/unoobj/shapeuno.cxx +++ b/sc/source/ui/unoobj/shapeuno.cxx @@ -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; }; } diff --git a/sc/source/ui/view/spellcheckcontext.cxx b/sc/source/ui/view/spellcheckcontext.cxx index b5bb141e54b5..a82c113488a1 100644 --- a/sc/source/ui/view/spellcheckcontext.cxx +++ b/sc/source/ui/view/spellcheckcontext.cxx @@ -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() diff --git a/sw/source/core/ole/ndole.cxx b/sw/source/core/ole/ndole.cxx index 8c95d59e1cf6..2ffc4f78a964 100644 --- a/sw/source/core/ole/ndole.cxx +++ b/sw/source/core/ole/ndole.cxx @@ -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 ) diff --git a/vcl/Library_vcl.mk b/vcl/Library_vcl.mk index bb69f1ba0297..20062dade35f 100644 --- a/vcl/Library_vcl.mk +++ b/vcl/Library_vcl.mk @@ -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 \ diff --git a/vcl/inc/TextLayoutCache.hxx b/vcl/inc/TextLayoutCache.hxx index 304c6d51ebfb..7c74e4974545 100644 --- a/vcl/inc/TextLayoutCache.hxx +++ b/vcl/inc/TextLayoutCache.hxx @@ -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&); diff --git a/vcl/inc/graphic/Manager.hxx b/vcl/inc/graphic/Manager.hxx index efef7f5ed683..a036fc21b8a7 100644 --- a/vcl/inc/graphic/Manager.hxx +++ b/vcl/inc/graphic/Manager.hxx @@ -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; }; diff --git a/vcl/inc/svcache.hxx b/vcl/inc/svcache.hxx new file mode 100644 index 000000000000..5f08197619a3 --- /dev/null +++ b/vcl/inc/svcache.hxx @@ -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: */ diff --git a/vcl/source/app/svcache.cxx b/vcl/source/app/svcache.cxx new file mode 100644 index 000000000000..6f8c2356b95c --- /dev/null +++ b/vcl/source/app/svcache.cxx @@ -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: */ diff --git a/vcl/source/app/svdata.cxx b/vcl/source/app/svdata.cxx index 6d32a2d22076..380c88c4a43c 100644 --- a/vcl/source/app/svdata.cxx +++ b/vcl/source/app/svdata.cxx @@ -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) diff --git a/vcl/source/gdi/impglyphitem.cxx b/vcl/source/gdi/impglyphitem.cxx index 78137c73370e..a8e72bbc30f0 100644 --- a/vcl/source/gdi/impglyphitem.cxx +++ b/vcl/source/gdi/impglyphitem.cxx @@ -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) { diff --git a/vcl/source/graphic/Manager.cxx b/vcl/source/graphic/Manager.cxx index 17f25cedec7c..bafa2711cbff 100644 --- a/vcl/source/graphic/Manager.cxx +++ b/vcl/source/graphic/Manager.cxx @@ -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) diff --git a/vcl/source/outdev/textline.cxx b/vcl/source/outdev/textline.cxx index d31de8494c59..bde74b2a494c 100644 --- a/vcl/source/outdev/textline.cxx +++ b/vcl/source/outdev/textline.cxx @@ -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 diff --git a/vcl/source/text/TextLayoutCache.cxx b/vcl/source/text/TextLayoutCache.cxx index 1a7c6ab521cf..b4f3799802a5 100644 --- a/vcl/source/text/TextLayoutCache.cxx +++ b/vcl/source/text/TextLayoutCache.cxx @@ -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()); } } diff --git a/vcl/unx/generic/fontmanager/fontconfig.cxx b/vcl/unx/generic/fontmanager/fontconfig.cxx index 80054e28bc7f..95ed5a19b5fc 100644 --- a/vcl/unx/generic/fontmanager/fontconfig.cxx +++ b/vcl/unx/generic/fontmanager/fontconfig.cxx @@ -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 diff --git a/vcl/unx/generic/gdi/cairotextrender.cxx b/vcl/unx/generic/gdi/cairotextrender.cxx index a00d0db9b544..14ee838df33d 100644 --- a/vcl/unx/generic/gdi/cairotextrender.cxx +++ b/vcl/unx/generic/gdi/cairotextrender.cxx @@ -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 + { + return "CairoFontsCache"; + } + + virtual bool dropCaches() override { - maLRUFonts.clear(); + 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; }