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:
Michael Meeks
2023-03-11 21:03:05 +00:00
parent 9dec458e40
commit 4a4602ad75
12 changed files with 149 additions and 9 deletions
+2 -1
View File
@@ -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));
+8
View File
@@ -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)
+4
View File
@@ -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)
+17
View File
@@ -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.
+4
View File
@@ -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);
}
+6 -2
View File
@@ -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);
+2
View File
@@ -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: */
+7
View File
@@ -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();
+21
View File
@@ -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
+23
View File
@@ -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())
+25
View File
@@ -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);
+30 -6
View File
@@ -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())