1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <graphic/Manager.hxx>
21 #include <impgraph.hxx>
22 #include <sal/log.hxx>
24 #include <officecfg/Office/Common.hxx>
25 #include <unotools/configmgr.hxx>
31 void setupConfigurationValuesIfPossible(sal_Int64
& rMemoryLimit
,
32 std::chrono::seconds
& rAllowedIdleTime
, bool& bSwapEnabled
)
34 if (comphelper::IsFuzzing())
39 using officecfg::Office::Common::Cache
;
41 rMemoryLimit
= Cache::GraphicManager::GraphicMemoryLimit::get();
43 = std::chrono::seconds(Cache::GraphicManager::GraphicAllowedIdleTime::get());
44 bSwapEnabled
= Cache::GraphicManager::GraphicSwappingEnabled::get();
52 namespace vcl::graphic
54 MemoryManager::MemoryManager()
55 : maSwapOutTimer("MemoryManager::MemoryManager maSwapOutTimer")
57 setupConfigurationValuesIfPossible(mnMemoryLimit
, mnAllowedIdleTime
, mbSwapEnabled
);
61 maSwapOutTimer
.SetInvokeHandler(LINK(this, MemoryManager
, ReduceMemoryTimerHandler
));
62 maSwapOutTimer
.SetTimeout(mnTimeout
);
63 maSwapOutTimer
.Start();
67 MemoryManager
& MemoryManager::get()
69 static MemoryManager gStaticManager
;
70 return gStaticManager
;
73 IMPL_LINK(MemoryManager
, ReduceMemoryTimerHandler
, Timer
*, pTimer
, void)
75 std::unique_lock
aGuard(maMutex
);
81 void MemoryManager::registerObject(MemoryManaged
* pMemoryManaged
)
83 std::unique_lock
aGuard(maMutex
);
85 // Insert and update the used size (bytes)
86 assert(aGuard
.owns_lock() && aGuard
.mutex() == &maMutex
);
87 // coverity[missing_lock: FALSE] - as above assert
88 mnTotalSize
+= pMemoryManaged
->getCurrentSizeInBytes();
89 maObjectList
.insert(pMemoryManaged
);
92 void MemoryManager::unregisterObject(MemoryManaged
* pMemoryManaged
)
94 std::unique_lock
aGuard(maMutex
);
95 mnTotalSize
-= pMemoryManaged
->getCurrentSizeInBytes();
96 maObjectList
.erase(pMemoryManaged
);
99 void MemoryManager::changeExisting(MemoryManaged
* pMemoryManaged
, sal_Int64 nNewSize
)
101 std::scoped_lock
aGuard(maMutex
);
102 sal_Int64 nOldSize
= pMemoryManaged
->getCurrentSizeInBytes();
103 mnTotalSize
-= nOldSize
;
104 mnTotalSize
+= nNewSize
;
105 pMemoryManaged
->setCurrentSizeInBytes(nNewSize
);
108 void MemoryManager::swappedIn(MemoryManaged
* pMemoryManaged
, sal_Int64 nNewSize
)
110 changeExisting(pMemoryManaged
, nNewSize
);
113 void MemoryManager::swappedOut(MemoryManaged
* pMemoryManaged
, sal_Int64 nNewSize
)
115 changeExisting(pMemoryManaged
, nNewSize
);
118 void MemoryManager::reduceAllAndNow()
120 std::unique_lock
aGuard(maMutex
);
121 reduceMemory(aGuard
, true);
124 void MemoryManager::dumpState(rtl::OStringBuffer
& rState
)
126 std::unique_lock
aGuard(maMutex
);
128 rState
.append("\nMemory Manager items:\t");
129 rState
.append(static_cast<sal_Int32
>(maObjectList
.size()));
130 rState
.append("\tsize:\t");
131 rState
.append(static_cast<sal_Int64
>(mnTotalSize
/ 1024));
132 rState
.append("\tkb");
134 for (MemoryManaged
* pMemoryManaged
: maObjectList
)
136 pMemoryManaged
->dumpState(rState
);
140 void MemoryManager::reduceMemory(std::unique_lock
<std::mutex
>& rGuard
, bool bDropAll
)
142 // maMutex is locked in callers
147 if (mnTotalSize
< mnMemoryLimit
&& !bDropAll
)
150 // avoid recursive reduceGraphicMemory on reexport of tdf118346-1.odg to odg
151 if (mbReducingGraphicMemory
)
154 mbReducingGraphicMemory
= true;
156 loopAndReduceMemory(rGuard
, bDropAll
);
158 mbReducingGraphicMemory
= false;
161 void MemoryManager::loopAndReduceMemory(std::unique_lock
<std::mutex
>& rGuard
, bool bDropAll
)
163 // make a copy of m_pImpGraphicList because if we swap out a svg, the svg
164 // filter may create more temp Graphics which are auto-added to
165 // m_pImpGraphicList invalidating a loop over m_pImpGraphicList, e.g.
166 // reexport of tdf118346-1.odg
168 o3tl::sorted_vector
<MemoryManaged
*> aObjectListCopy
= maObjectList
;
170 for (MemoryManaged
* pMemoryManaged
: aObjectListCopy
)
172 if (!pMemoryManaged
->canReduceMemory())
175 sal_Int64 nCurrentSizeInBytes
= pMemoryManaged
->getCurrentSizeInBytes();
176 if (nCurrentSizeInBytes
> mnSmallFrySize
|| bDropAll
) // ignore small-fry
178 auto aCurrent
= std::chrono::high_resolution_clock::now();
179 auto aDeltaTime
= aCurrent
- pMemoryManaged
->getLastUsed();
180 auto aSeconds
= std::chrono::duration_cast
<std::chrono::seconds
>(aDeltaTime
);
182 if (aSeconds
> mnAllowedIdleTime
)
184 // unlock because svgio can call back into us
186 pMemoryManaged
->reduceMemory();
193 } // end vcl::graphic
195 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */