include/o3tl/lru_map.hxx | 32 ++++- include/o3tl/numeric.hxx | 6 + 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, 428 insertions(+), 51 deletions(-)
New commits: commit b8935ee3b43e515b4a2810bb51a8bf17b90b7446 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: Fri Jul 4 16:47:27 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/+/186269 Tested-by: Caolán McNamara <caolan.mcnam...@collabora.com> Reviewed-by: Caolán McNamara <caolan.mcnam...@collabora.com> Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.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 9980319a648b..0a872e8dd764 100644 --- a/include/o3tl/numeric.hxx +++ b/include/o3tl/numeric.hxx @@ -10,6 +10,7 @@ #ifndef INCLUDED_O3TL_NUMERIC_HXX #define INCLUDED_O3TL_NUMERIC_HXX +#include <bit> #include <stdexcept> namespace o3tl @@ -21,6 +22,11 @@ namespace o3tl { } }; + + template<class T> constexpr unsigned int number_of_bits(T x) + { + return sizeof(T) * 8 - std::countl_zero(x); + } } #endif diff --git a/include/vcl/dropcache.hxx b/include/vcl/dropcache.hxx index 3a9854f203f9..588242506311 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 namespace rtl { @@ -23,8 +28,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 88d31031e7ba..1b6f1184640f 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 @@ -245,7 +251,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 23b0d1dfeb4b..d3b77a5029f7 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 5a8b57f5482a..6674cb1ab1a6 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 f8a6de5b5c2a..3dcb879b5c51 100644 --- a/vcl/Library_vcl.mk +++ b/vcl/Library_vcl.mk @@ -418,6 +418,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 303e01dbfca4..912de070fad3 100644 --- a/vcl/source/app/svdata.cxx +++ b/vcl/source/app/svdata.cxx @@ -44,6 +44,7 @@ #include <vcl/toolkit/dialog.hxx> #include <salinst.hxx> #include <salgdi.hxx> +#include <svcache.hxx> #include <svdata.hxx> #include <salsys.hxx> #include <windowdev.hxx> @@ -448,24 +449,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 87a2591ab77c..df9e42fd34e6 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 80110829d99a..a5afbbe2d93f 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; }