diff options
author | Tomaž Vajngerl <tomaz.vajngerl@collabora.co.uk> | 2024-03-18 00:17:54 +0900 |
---|---|---|
committer | Tomaž Vajngerl <quikee@gmail.com> | 2024-03-30 15:21:10 +0100 |
commit | 324f2e135427f2f24cf7eb9a4fab4aa903329ae5 (patch) | |
tree | bdcf04a1cd47b22a7612e903f9c68aef17c1dc41 /vcl/source/graphic | |
parent | 174430d7a831eede078b6718d991b506d39180f1 (diff) |
vcl: change (graphic) Manager into a general memory manager
Graphic memory manager was changes so that it can work with any
object that implements a specific interface (MemoryManaged). With
this it will be possible to use other objects (that take a lot of
memory) to be managed by the manager. It is also a first step to
move memory managin responsibilities away from Graphic and move
it into the specific objects instead (BitmapEx, Animation and
VectorGraphic).
Change-Id: I7638bd89a1c9ece5c4bc95b506d2192492894ef3
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/164958
Tested-by: Jenkins
Reviewed-by: Tomaž Vajngerl <quikee@gmail.com>
Diffstat (limited to 'vcl/source/graphic')
-rw-r--r-- | vcl/source/graphic/Manager.cxx | 286 |
1 files changed, 82 insertions, 204 deletions
diff --git a/vcl/source/graphic/Manager.cxx b/vcl/source/graphic/Manager.cxx index 4bb4ce79534b..fb316aef153d 100644 --- a/vcl/source/graphic/Manager.cxx +++ b/vcl/source/graphic/Manager.cxx @@ -26,8 +26,6 @@ using namespace css; -namespace vcl::graphic -{ namespace { void setupConfigurationValuesIfPossible(sal_Int64& rMemoryLimit, @@ -51,267 +49,147 @@ void setupConfigurationValuesIfPossible(sal_Int64& rMemoryLimit, } } -Manager& Manager::get() +namespace vcl::graphic { - static Manager gStaticManager; - return gStaticManager; -} - -Manager::Manager() - : mnAllowedIdleTime(10) - , mbSwapEnabled(true) - , mbReducingGraphicMemory(false) - , mnMemoryLimit(300000000) - , mnUsedSize(0) - , maSwapOutTimer("graphic::Manager maSwapOutTimer") +MemoryManager::MemoryManager() + : maSwapOutTimer("MemoryManager::MemoryManager maSwapOutTimer") { setupConfigurationValuesIfPossible(mnMemoryLimit, mnAllowedIdleTime, mbSwapEnabled); if (mbSwapEnabled) { - maSwapOutTimer.SetInvokeHandler(LINK(this, Manager, SwapOutTimerHandler)); - maSwapOutTimer.SetTimeout(10000); + maSwapOutTimer.SetInvokeHandler(LINK(this, MemoryManager, ReduceMemoryTimerHandler)); + maSwapOutTimer.SetTimeout(mnTimeout); maSwapOutTimer.Start(); } } -void Manager::loopGraphicsAndSwapOut(std::unique_lock<std::mutex>& rGuard, bool bDropAll) +MemoryManager& MemoryManager::get() { - // make a copy of m_pImpGraphicList because if we swap out a svg, the svg - // filter may create more temp Graphics which are auto-added to - // m_pImpGraphicList invalidating a loop over m_pImpGraphicList, e.g. - // reexport of tdf118346-1.odg - o3tl::sorted_vector<ImpGraphic*> aImpGraphicList = m_pImpGraphicList; - - for (ImpGraphic* pEachImpGraphic : aImpGraphicList) - { - if (mnUsedSize < sal_Int64(mnMemoryLimit * 0.7) && !bDropAll) - return; - - if (pEachImpGraphic->isSwappedOut()) - continue; - - sal_Int64 nCurrentGraphicSize = getGraphicSizeBytes(pEachImpGraphic); - if (nCurrentGraphicSize > 100000 || bDropAll) - { - if (!pEachImpGraphic->mpContext) - { - auto aCurrent = std::chrono::high_resolution_clock::now(); - auto aDeltaTime = aCurrent - pEachImpGraphic->maLastUsed; - auto aSeconds = std::chrono::duration_cast<std::chrono::seconds>(aDeltaTime); - - if (aSeconds > mnAllowedIdleTime) - { - // unlock because svgio can call back into us - rGuard.unlock(); - pEachImpGraphic->swapOut(); - rGuard.lock(); - } - } - } - } + static MemoryManager gStaticManager; + return gStaticManager; } -void Manager::reduceGraphicMemory(std::unique_lock<std::mutex>& rGuard, bool bDropAll) +IMPL_LINK(MemoryManager, ReduceMemoryTimerHandler, Timer*, pTimer, void) { - // maMutex is locked in callers - - if (!mbSwapEnabled) - return; - - if (mnUsedSize < mnMemoryLimit && !bDropAll) - return; - - // avoid recursive reduceGraphicMemory on reexport of tdf118346-1.odg to odg - if (mbReducingGraphicMemory) - return; - - mbReducingGraphicMemory = true; - - loopGraphicsAndSwapOut(rGuard, bDropAll); - - sal_Int64 calculatedSize = 0; - for (ImpGraphic* pEachImpGraphic : m_pImpGraphicList) - { - if (!pEachImpGraphic->isSwappedOut()) - { - calculatedSize += getGraphicSizeBytes(pEachImpGraphic); - } - } - - if (calculatedSize != mnUsedSize) - { - assert(rGuard.owns_lock() && rGuard.mutex() == &maMutex); - // coverity[missing_lock: FALSE] - as above assert - mnUsedSize = calculatedSize; - } - - mbReducingGraphicMemory = false; + std::unique_lock aGuard(maMutex); + pTimer->Stop(); + reduceMemory(aGuard); + pTimer->Start(); } -void Manager::dropCache() +void MemoryManager::registerObject(MemoryManaged* pMemoryManaged) { std::unique_lock aGuard(maMutex); - reduceGraphicMemory(aGuard, true); + // Insert and update the used size (bytes) + assert(aGuard.owns_lock() && aGuard.mutex() == &maMutex); + // coverity[missing_lock: FALSE] - as above assert + mnTotalSize += pMemoryManaged->getCurrentSizeInBytes(); + maObjectList.insert(pMemoryManaged); } -void Manager::dumpState(rtl::OStringBuffer& rState) +void MemoryManager::unregisterObject(MemoryManaged* pMemoryManaged) { std::unique_lock aGuard(maMutex); + mnTotalSize -= pMemoryManaged->getCurrentSizeInBytes(); + maObjectList.erase(pMemoryManaged); +} - rState.append("\nImage Manager items:\t"); - rState.append(static_cast<sal_Int32>(m_pImpGraphicList.size())); - rState.append("\tsize:\t"); - rState.append(static_cast<sal_Int64>(mnUsedSize / 1024)); - rState.append("\tkb"); +void MemoryManager::changeExisting(MemoryManaged* pMemoryManaged, sal_Int64 nNewSize) +{ + std::scoped_lock aGuard(maMutex); + sal_Int64 nOldSize = pMemoryManaged->getCurrentSizeInBytes(); + mnTotalSize -= nOldSize; + mnTotalSize += nNewSize; + pMemoryManaged->setCurrentSizeInBytes(nNewSize); +} - for (ImpGraphic* pEachImpGraphic : m_pImpGraphicList) - { - pEachImpGraphic->dumpState(rState); - } +void MemoryManager::swappedIn(MemoryManaged* pMemoryManaged, sal_Int64 nNewSize) +{ + changeExisting(pMemoryManaged, nNewSize); } -sal_Int64 Manager::getGraphicSizeBytes(const ImpGraphic* pImpGraphic) +void MemoryManager::swappedOut(MemoryManaged* pMemoryManaged, sal_Int64 nNewSize) { - if (!pImpGraphic->isAvailable()) - return 0; - return pImpGraphic->getSizeBytes(); + changeExisting(pMemoryManaged, nNewSize); } -IMPL_LINK(Manager, SwapOutTimerHandler, Timer*, pTimer, void) +void MemoryManager::reduceAllAndNow() { std::unique_lock aGuard(maMutex); - - pTimer->Stop(); - reduceGraphicMemory(aGuard); - pTimer->Start(); + reduceMemory(aGuard, true); } -void Manager::registerGraphic(const std::shared_ptr<ImpGraphic>& pImpGraphic) +void MemoryManager::dumpState(rtl::OStringBuffer& rState) { std::unique_lock aGuard(maMutex); - // make some space first - if (mnUsedSize > mnMemoryLimit) - reduceGraphicMemory(aGuard); - - // Insert and update the used size (bytes) - assert(aGuard.owns_lock() && aGuard.mutex() == &maMutex); - // coverity[missing_lock: FALSE] - as above assert - mnUsedSize += getGraphicSizeBytes(pImpGraphic.get()); - m_pImpGraphicList.insert(pImpGraphic.get()); - - // calculate size of the graphic set - sal_Int64 calculatedSize = 0; - for (ImpGraphic* pEachImpGraphic : m_pImpGraphicList) - { - if (!pEachImpGraphic->isSwappedOut()) - { - calculatedSize += getGraphicSizeBytes(pEachImpGraphic); - } - } + rState.append("\nMemory Manager items:\t"); + rState.append(static_cast<sal_Int32>(maObjectList.size())); + rState.append("\tsize:\t"); + rState.append(static_cast<sal_Int64>(mnTotalSize / 1024)); + rState.append("\tkb"); - if (calculatedSize != mnUsedSize) + for (MemoryManaged* pMemoryManaged : maObjectList) { - SAL_INFO_IF(calculatedSize != mnUsedSize, "vcl.gdi", - "Calculated size mismatch. Variable size is '" - << mnUsedSize << "' but calculated size is '" << calculatedSize << "'"); - mnUsedSize = calculatedSize; + pMemoryManaged->dumpState(rState); } } -void Manager::unregisterGraphic(ImpGraphic* pImpGraphic) +void MemoryManager::reduceMemory(std::unique_lock<std::mutex>& rGuard, bool bDropAll) { - std::scoped_lock aGuard(maMutex); - - mnUsedSize -= getGraphicSizeBytes(pImpGraphic); - m_pImpGraphicList.erase(pImpGraphic); -} + // maMutex is locked in callers -std::shared_ptr<ImpGraphic> Manager::copy(std::shared_ptr<ImpGraphic> const& rImpGraphicPtr) -{ - auto pReturn = std::make_shared<ImpGraphic>(*rImpGraphicPtr); - registerGraphic(pReturn); - return pReturn; -} + if (!mbSwapEnabled) + return; -std::shared_ptr<ImpGraphic> Manager::newInstance() -{ - auto pReturn = std::make_shared<ImpGraphic>(); - registerGraphic(pReturn); - return pReturn; -} + if (mnTotalSize < mnMemoryLimit && !bDropAll) + return; -std::shared_ptr<ImpGraphic> Manager::newInstance(std::shared_ptr<GfxLink> const& rGfxLink, - sal_Int32 nPageIndex) -{ - auto pReturn = std::make_shared<ImpGraphic>(rGfxLink, nPageIndex); - registerGraphic(pReturn); - return pReturn; -} + // avoid recursive reduceGraphicMemory on reexport of tdf118346-1.odg to odg + if (mbReducingGraphicMemory) + return; -std::shared_ptr<ImpGraphic> Manager::newInstance(const BitmapEx& rBitmapEx) -{ - auto pReturn = std::make_shared<ImpGraphic>(rBitmapEx); - registerGraphic(pReturn); - return pReturn; -} + mbReducingGraphicMemory = true; -std::shared_ptr<ImpGraphic> Manager::newInstance(const Animation& rAnimation) -{ - auto pReturn = std::make_shared<ImpGraphic>(rAnimation); - registerGraphic(pReturn); - return pReturn; -} + loopAndReduceMemory(rGuard, bDropAll); -std::shared_ptr<ImpGraphic> -Manager::newInstance(const std::shared_ptr<VectorGraphicData>& rVectorGraphicDataPtr) -{ - auto pReturn = std::make_shared<ImpGraphic>(rVectorGraphicDataPtr); - registerGraphic(pReturn); - return pReturn; + mbReducingGraphicMemory = false; } -std::shared_ptr<ImpGraphic> Manager::newInstance(const GDIMetaFile& rMetaFile) +void MemoryManager::loopAndReduceMemory(std::unique_lock<std::mutex>& rGuard, bool bDropAll) { - auto pReturn = std::make_shared<ImpGraphic>(rMetaFile); - registerGraphic(pReturn); - return pReturn; -} + // make a copy of m_pImpGraphicList because if we swap out a svg, the svg + // filter may create more temp Graphics which are auto-added to + // m_pImpGraphicList invalidating a loop over m_pImpGraphicList, e.g. + // reexport of tdf118346-1.odg -std::shared_ptr<ImpGraphic> Manager::newInstance(const GraphicExternalLink& rGraphicLink) -{ - auto pReturn = std::make_shared<ImpGraphic>(rGraphicLink); - registerGraphic(pReturn); - return pReturn; -} + o3tl::sorted_vector<MemoryManaged*> aObjectListCopy = maObjectList; -void Manager::swappedIn(const ImpGraphic* pImpGraphic, sal_Int64 nSizeBytes) -{ - std::scoped_lock aGuard(maMutex); - if (pImpGraphic) + for (MemoryManaged* pMemoryManaged : aObjectListCopy) { - mnUsedSize += nSizeBytes; - } -} + if (!pMemoryManaged->canReduceMemory()) + continue; -void Manager::swappedOut(const ImpGraphic* pImpGraphic, sal_Int64 nSizeBytes) -{ - std::scoped_lock aGuard(maMutex); - if (pImpGraphic) - { - mnUsedSize -= nSizeBytes; + sal_Int64 nCurrentSizeInBytes = pMemoryManaged->getCurrentSizeInBytes(); + if (nCurrentSizeInBytes > mnSmallFrySize || bDropAll) // ignore small-fry + { + auto aCurrent = std::chrono::high_resolution_clock::now(); + auto aDeltaTime = aCurrent - pMemoryManaged->getLastUsed(); + auto aSeconds = std::chrono::duration_cast<std::chrono::seconds>(aDeltaTime); + + if (aSeconds > mnAllowedIdleTime) + { + // unlock because svgio can call back into us + rGuard.unlock(); + pMemoryManaged->reduceMemory(); + rGuard.lock(); + } + } } } -void Manager::changeExisting(const ImpGraphic* pImpGraphic, sal_Int64 nOldSizeBytes) -{ - std::scoped_lock aGuard(maMutex); - - mnUsedSize -= nOldSizeBytes; - mnUsedSize += getGraphicSizeBytes(pImpGraphic); -} } // end vcl::graphic /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |