lok: add trimMemory capability, and expand dumpState to caches.
Being able to trigger some more aggressive memory saving is useful in for both online and mobile. Change-Id: I9b91c9fe9eecec06c75112595deac0bfeb94c144 Signed-off-by: Michael Meeks <michael.meeks@collabora.com> Reviewed-on: https://gerrit.libreoffice.org/c/core/+/148624 Tested-by: Jenkins
This commit is contained in:
@@ -3554,10 +3554,11 @@ void DesktopLOKTest::testABI()
|
||||
CPPUNIT_ASSERT_EQUAL(classOffset(14), offsetof(struct _LibreOfficeKitClass, setOption));
|
||||
CPPUNIT_ASSERT_EQUAL(classOffset(15), offsetof(struct _LibreOfficeKitClass, dumpState));
|
||||
CPPUNIT_ASSERT_EQUAL(classOffset(16), offsetof(struct _LibreOfficeKitClass, extractRequest));
|
||||
CPPUNIT_ASSERT_EQUAL(classOffset(17), offsetof(struct _LibreOfficeKitClass, trimMemory));
|
||||
|
||||
// When extending LibreOfficeKit with a new function pointer, add new assert for the offsetof the
|
||||
// new function pointer and bump this assert for the size of the class.
|
||||
CPPUNIT_ASSERT_EQUAL(classOffset(17), sizeof(struct _LibreOfficeKitClass));
|
||||
CPPUNIT_ASSERT_EQUAL(classOffset(18), sizeof(struct _LibreOfficeKitClass));
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(documentClassOffset(0), offsetof(struct _LibreOfficeKitDocumentClass, destroy));
|
||||
CPPUNIT_ASSERT_EQUAL(documentClassOffset(1), offsetof(struct _LibreOfficeKitDocumentClass, saveAs));
|
||||
|
||||
@@ -2523,6 +2523,8 @@ static bool lo_signDocument(LibreOfficeKit* pThis,
|
||||
static char* lo_extractRequest(LibreOfficeKit* pThis,
|
||||
const char* pFilePath);
|
||||
|
||||
static void lo_trimMemory(LibreOfficeKit* pThis, int nTarget);
|
||||
|
||||
static void lo_runLoop(LibreOfficeKit* pThis,
|
||||
LibreOfficeKitPollCallback pPollCallback,
|
||||
LibreOfficeKitWakeCallback pWakeCallback,
|
||||
@@ -2564,6 +2566,7 @@ LibLibreOffice_Impl::LibLibreOffice_Impl()
|
||||
m_pOfficeClass->setOption = lo_setOption;
|
||||
m_pOfficeClass->dumpState = lo_dumpState;
|
||||
m_pOfficeClass->extractRequest = lo_extractRequest;
|
||||
m_pOfficeClass->trimMemory = lo_trimMemory;
|
||||
|
||||
gOfficeClass = m_pOfficeClass;
|
||||
}
|
||||
@@ -3142,6 +3145,11 @@ static char* lo_extractRequest(LibreOfficeKit* /*pThis*/, const char* pFilePath)
|
||||
return convertOUString(result);
|
||||
}
|
||||
|
||||
static void lo_trimMemory(LibreOfficeKit* /* pThis */, int nTarget)
|
||||
{
|
||||
vcl::lok::trimMemory(nTarget);
|
||||
}
|
||||
|
||||
static void lo_registerCallback (LibreOfficeKit* pThis,
|
||||
LibreOfficeKitCallback pCallback,
|
||||
void* pData)
|
||||
|
||||
@@ -127,6 +127,10 @@ struct _LibreOfficeKitClass
|
||||
*/
|
||||
char* (*extractRequest) (LibreOfficeKit* pThis,
|
||||
const char* pFilePath);
|
||||
|
||||
/// @see lok::Office::trimMemory
|
||||
/// @since LibreOffice 7.6
|
||||
void (*trimMemory) (LibreOfficeKit* pThis, int nTarget);
|
||||
};
|
||||
|
||||
#define LIBREOFFICEKIT_DOCUMENT_HAS(pDoc,member) LIBREOFFICEKIT_HAS_MEMBER(LibreOfficeKitDocumentClass,member,(pDoc)->pClass->nSize)
|
||||
|
||||
@@ -1146,6 +1146,23 @@ public:
|
||||
{
|
||||
return mpThis->pClass->extractRequest(mpThis, pFilePath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Trim memory usage.
|
||||
*
|
||||
* LibreOfficeKit caches lots of information from large pixmaps
|
||||
* to view and calculation results. When a view has not been
|
||||
* used for some time, depending on the load on memory it can
|
||||
* be useful to free up memory.
|
||||
*
|
||||
* @param nTarget - a negative number means the app is back
|
||||
* in active use, and to re-fill caches, a large positive
|
||||
* number (>=1000) encourages immediate maximum memory saving.
|
||||
*/
|
||||
void trimMemory (int nTarget)
|
||||
{
|
||||
mpThis->pClass->trimMemory(mpThis, nTarget);
|
||||
}
|
||||
};
|
||||
|
||||
/// Factory method to create a lok::Office instance.
|
||||
|
||||
@@ -26,6 +26,10 @@ void VCL_DLLPUBLIC unregisterPollCallbacks();
|
||||
// can adjust e.g. sizes of bitmap caches to scale well with larger number of users.
|
||||
void VCL_DLLPUBLIC numberOfViewsChanged(int count);
|
||||
|
||||
// Trim memory use by wiping various internal caches
|
||||
void VCL_DLLPUBLIC trimMemory(int nTarget);
|
||||
|
||||
// Dump internal state of VCL windows etc. for debugging
|
||||
void VCL_DLLPUBLIC dumpState(rtl::OStringBuffer& rState);
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#define INCLUDED_VCL_INC_GRAPHIC_MANAGER_HXX
|
||||
|
||||
#include <sal/types.h>
|
||||
#include <rtl/strbuf.hxx>
|
||||
#include <rtl/ustring.hxx>
|
||||
#include <vcl/bitmapex.hxx>
|
||||
#include <vcl/animate/Animation.hxx>
|
||||
@@ -43,16 +44,19 @@ private:
|
||||
Manager();
|
||||
|
||||
void registerGraphic(const std::shared_ptr<ImpGraphic>& rImpGraphic);
|
||||
void loopGraphicsAndSwapOut(std::unique_lock<std::mutex>& rGuard);
|
||||
void loopGraphicsAndSwapOut(std::unique_lock<std::mutex>& rGuard, bool bDropAll);
|
||||
|
||||
DECL_LINK(SwapOutTimerHandler, Timer*, void);
|
||||
|
||||
static sal_Int64 getGraphicSizeBytes(const ImpGraphic* pImpGraphic);
|
||||
void reduceGraphicMemory(std::unique_lock<std::mutex>& rGuard);
|
||||
void reduceGraphicMemory(std::unique_lock<std::mutex>& rGuard, bool bDropAll = false);
|
||||
|
||||
public:
|
||||
static Manager& get();
|
||||
|
||||
void dropCache();
|
||||
void dumpState(rtl::OStringBuffer& rState);
|
||||
|
||||
void swappedIn(const ImpGraphic* pImpGraphic, sal_Int64 nSizeBytes);
|
||||
void swappedOut(const ImpGraphic* pImpGraphic, sal_Int64 nSizeBytes);
|
||||
|
||||
|
||||
@@ -47,6 +47,7 @@ class GfxLink;
|
||||
class ImpSwapFile;
|
||||
class GraphicConversionParameters;
|
||||
class ImpGraphic;
|
||||
namespace rtl { class OStringBuffer; }
|
||||
|
||||
enum class GraphicContentType : sal_Int32
|
||||
{
|
||||
@@ -219,6 +220,7 @@ public:
|
||||
SvStream* getSwapFileStream() const;
|
||||
// public only because of use in GraphicFilter
|
||||
void updateFromLoadedGraphic(const ImpGraphic* graphic);
|
||||
void dumpState(rtl::OStringBuffer &rState);
|
||||
};
|
||||
|
||||
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|
||||
|
||||
@@ -54,6 +54,10 @@ struct ImplPostEventData;
|
||||
struct ImplTimerData;
|
||||
struct ImplIdleData;
|
||||
struct ImplConfigData;
|
||||
namespace rtl
|
||||
{
|
||||
class OStringBuffer;
|
||||
}
|
||||
namespace vcl::font
|
||||
{
|
||||
class DirectFontSubstitution;
|
||||
@@ -431,6 +435,9 @@ struct ImplSVData
|
||||
LibreOfficeKitPollCallback mpPollCallback = nullptr;
|
||||
LibreOfficeKitWakeCallback mpWakeCallback = nullptr;
|
||||
void *mpPollClosure = nullptr;
|
||||
|
||||
void dropCaches();
|
||||
void dumpState(rtl::OStringBuffer &rState);
|
||||
};
|
||||
|
||||
css::uno::Reference<css::i18n::XCharacterClassification> const& ImplGetCharClass();
|
||||
|
||||
@@ -54,6 +54,7 @@
|
||||
#include <vcl/skia/SkiaHelper.hxx>
|
||||
|
||||
#include <salinst.hxx>
|
||||
#include <graphic/Manager.hxx>
|
||||
#include <salframe.hxx>
|
||||
#include <salsys.hxx>
|
||||
#include <svdata.hxx>
|
||||
@@ -69,6 +70,7 @@
|
||||
#include <com/sun/star/uno/Reference.h>
|
||||
#include <com/sun/star/awt/XToolkit.hpp>
|
||||
#include <comphelper/lok.hxx>
|
||||
#include <comphelper/threadpool.hxx>
|
||||
#include <comphelper/solarmutex.hxx>
|
||||
#include <osl/process.h>
|
||||
|
||||
@@ -1870,6 +1872,25 @@ void dumpState(rtl::OStringBuffer &rState)
|
||||
|
||||
pWin = Application::GetNextTopLevelWindow( pWin );
|
||||
}
|
||||
|
||||
vcl::graphic::Manager::get().dumpState(rState);
|
||||
|
||||
pSVData->dumpState(rState);
|
||||
}
|
||||
|
||||
void trimMemory(int nTarget)
|
||||
{
|
||||
if (nTarget >= 1000)
|
||||
{
|
||||
ImplSVData* pSVData = ImplGetSVData();
|
||||
if (!pSVData) // shutting down
|
||||
return;
|
||||
pSVData->dropCaches();
|
||||
vcl::graphic::Manager::get().dropCache();
|
||||
// TODO: ideally - free up any deeper dirtied thread stacks.
|
||||
// comphelper::ThreadPool::getSharedOptimalPool().shutdown();
|
||||
}
|
||||
// else for now caches re-fill themselves as/when used.
|
||||
}
|
||||
|
||||
} // namespace lok, namespace vcl
|
||||
|
||||
@@ -417,6 +417,29 @@ ImplSVData::ImplSVData()
|
||||
mpWinData = &private_aImplSVWinData::get();
|
||||
}
|
||||
|
||||
void ImplSVData::dropCaches()
|
||||
{
|
||||
maGDIData.maScaleCache.clear();
|
||||
maGDIData.maThemeImageCache.clear();
|
||||
maGDIData.maThemeDrawCommandsCache.clear();
|
||||
}
|
||||
|
||||
void ImplSVData::dumpState(rtl::OStringBuffer &rState)
|
||||
{
|
||||
rState.append("\nScaleCache:\t");
|
||||
rState.append(static_cast<sal_Int32>(maGDIData.maScaleCache.size()));
|
||||
rState.append("\t items:");
|
||||
|
||||
for (auto it = maGDIData.maScaleCache.begin();
|
||||
it != maGDIData.maScaleCache.begin(); ++it)
|
||||
{
|
||||
rState.append("\n\t");
|
||||
rState.append(static_cast<sal_Int32>(it->first.maDestSize.Width()));
|
||||
rState.append("x");
|
||||
rState.append(static_cast<sal_Int32>(it->first.maDestSize.Height()));
|
||||
}
|
||||
}
|
||||
|
||||
ImplSVHelpData* CreateSVHelpData()
|
||||
{
|
||||
if (!comphelper::LibreOfficeKit::isActive())
|
||||
|
||||
@@ -1419,6 +1419,31 @@ void ImpGraphic::updateFromLoadedGraphic(const ImpGraphic* pGraphic)
|
||||
}
|
||||
}
|
||||
|
||||
void ImpGraphic::dumpState(rtl::OStringBuffer &rState)
|
||||
{
|
||||
if (meType == GraphicType::NONE && mnSizeBytes == 0)
|
||||
return; // uninteresting.
|
||||
|
||||
rState.append("\n\t");
|
||||
|
||||
if (mbSwapOut)
|
||||
rState.append("swapped\t");
|
||||
else
|
||||
rState.append("loaded\t");
|
||||
|
||||
rState.append(static_cast<sal_Int32>(meType));
|
||||
rState.append("\tsize:\t");
|
||||
rState.append(static_cast<sal_Int64>(mnSizeBytes));
|
||||
rState.append("\t");
|
||||
rState.append(static_cast<sal_Int32>(maSwapInfo.maSizePixel.Width()));
|
||||
rState.append("x");
|
||||
rState.append(static_cast<sal_Int32>(maSwapInfo.maSizePixel.Height()));
|
||||
rState.append("\t");
|
||||
rState.append(static_cast<sal_Int32>(maExPrefSize.Width()));
|
||||
rState.append("x");
|
||||
rState.append(static_cast<sal_Int32>(maExPrefSize.Height()));
|
||||
}
|
||||
|
||||
void ImpGraphic::restoreFromSwapInfo()
|
||||
{
|
||||
setValuesForPrefMapMod(maSwapInfo.maPrefMapMode);
|
||||
|
||||
@@ -75,7 +75,7 @@ Manager::Manager()
|
||||
}
|
||||
}
|
||||
|
||||
void Manager::loopGraphicsAndSwapOut(std::unique_lock<std::mutex>& rGuard)
|
||||
void Manager::loopGraphicsAndSwapOut(std::unique_lock<std::mutex>& rGuard, bool bDropAll)
|
||||
{
|
||||
// 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
|
||||
@@ -85,14 +85,14 @@ void Manager::loopGraphicsAndSwapOut(std::unique_lock<std::mutex>& rGuard)
|
||||
|
||||
for (ImpGraphic* pEachImpGraphic : aImpGraphicList)
|
||||
{
|
||||
if (mnUsedSize < sal_Int64(mnMemoryLimit * 0.7))
|
||||
if (mnUsedSize < sal_Int64(mnMemoryLimit * 0.7) && !bDropAll)
|
||||
return;
|
||||
|
||||
if (pEachImpGraphic->isSwappedOut())
|
||||
continue;
|
||||
|
||||
sal_Int64 nCurrentGraphicSize = getGraphicSizeBytes(pEachImpGraphic);
|
||||
if (nCurrentGraphicSize > 100000)
|
||||
if (nCurrentGraphicSize > 100000 || bDropAll)
|
||||
{
|
||||
if (!pEachImpGraphic->mpContext)
|
||||
{
|
||||
@@ -112,22 +112,23 @@ void Manager::loopGraphicsAndSwapOut(std::unique_lock<std::mutex>& rGuard)
|
||||
}
|
||||
}
|
||||
|
||||
void Manager::reduceGraphicMemory(std::unique_lock<std::mutex>& rGuard)
|
||||
void Manager::reduceGraphicMemory(std::unique_lock<std::mutex>& rGuard, bool bDropAll)
|
||||
{
|
||||
// maMutex is locked in callers
|
||||
|
||||
if (!mbSwapEnabled)
|
||||
return;
|
||||
|
||||
if (mnUsedSize < mnMemoryLimit)
|
||||
if (mnUsedSize < mnMemoryLimit && !bDropAll)
|
||||
return;
|
||||
|
||||
// avoid recursive reduceGraphicMemory on reexport of tdf118346-1.odg to odg
|
||||
if (mbReducingGraphicMemory)
|
||||
return;
|
||||
|
||||
mbReducingGraphicMemory = true;
|
||||
|
||||
loopGraphicsAndSwapOut(rGuard);
|
||||
loopGraphicsAndSwapOut(rGuard, bDropAll);
|
||||
|
||||
sal_Int64 calculatedSize = 0;
|
||||
for (ImpGraphic* pEachImpGraphic : m_pImpGraphicList)
|
||||
@@ -148,6 +149,29 @@ void Manager::reduceGraphicMemory(std::unique_lock<std::mutex>& rGuard)
|
||||
mbReducingGraphicMemory = false;
|
||||
}
|
||||
|
||||
void Manager::dropCache()
|
||||
{
|
||||
std::unique_lock aGuard(maMutex);
|
||||
|
||||
reduceGraphicMemory(aGuard, true);
|
||||
}
|
||||
|
||||
void Manager::dumpState(rtl::OStringBuffer& rState)
|
||||
{
|
||||
std::unique_lock aGuard(maMutex);
|
||||
|
||||
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");
|
||||
|
||||
for (ImpGraphic* pEachImpGraphic : m_pImpGraphicList)
|
||||
{
|
||||
pEachImpGraphic->dumpState(rState);
|
||||
}
|
||||
}
|
||||
|
||||
sal_Int64 Manager::getGraphicSizeBytes(const ImpGraphic* pImpGraphic)
|
||||
{
|
||||
if (!pImpGraphic->isAvailable())
|
||||
|
||||
Reference in New Issue
Block a user