sc/Library_sc.mk | 1 sc/inc/global.hxx | 8 +++ sc/source/core/data/documen2.cxx | 10 ++++ sc/source/core/data/global.cxx | 9 ++++ sc/source/core/inc/sharedstringpoolpurge.hxx | 48 +++++++++++++++++++++ sc/source/core/tool/sharedstringpoolpurge.cxx | 58 ++++++++++++++++++++++++++ 6 files changed, 133 insertions(+), 1 deletion(-)
New commits: commit 5b2a153779b68e8454a66973579512fe17e376d5 Author: Luboš Luňák <l.lu...@collabora.com> AuthorDate: Wed Feb 9 10:39:10 2022 +0100 Commit: Luboš Luňák <l.lu...@collabora.com> CommitDate: Thu Feb 10 15:18:48 2022 +0100 do not call purge() on string pool too often (tdf#125428) It turns out svl::SharedStringPool::purge() can be somewhat expensive with larger documents. Profiling suggests it's primarily the cost of the CPU trying to access the rtl_uString instances scattered all over the memory, so it can't be easily optimized. So instead delay and compress purge() calls if they come from temporary ScDocument instances from undo or clipboard. Change-Id: Ie26cce113025ff45ee2c473c6b06f684f453b27b Reviewed-on: https://gerrit.libreoffice.org/c/core/+/129713 Tested-by: Jenkins Reviewed-by: Luboš Luňák <l.lu...@collabora.com> diff --git a/sc/Library_sc.mk b/sc/Library_sc.mk index 973354175738..3e833cc44acf 100644 --- a/sc/Library_sc.mk +++ b/sc/Library_sc.mk @@ -279,6 +279,7 @@ $(eval $(call gb_Library_add_exception_objects,sc,\ sc/source/core/tool/scmatrix \ sc/source/core/tool/scopetools \ sc/source/core/tool/sharedformula \ + sc/source/core/tool/sharedstringpoolpurge \ sc/source/core/tool/stringutil \ sc/source/core/tool/stylehelper \ sc/source/core/tool/subtotal \ diff --git a/sc/inc/global.hxx b/sc/inc/global.hxx index 9d1199f9de8c..283231ddf5f1 100644 --- a/sc/inc/global.hxx +++ b/sc/inc/global.hxx @@ -488,6 +488,10 @@ namespace utl { class TransliterationWrapper; } +namespace sc { + class SharedStringPoolPurge; +} + class ScGlobal { static std::unique_ptr<SvxSearchItem> xSearchItem; @@ -516,6 +520,8 @@ class ScGlobal static std::unique_ptr<ScFieldEditEngine> xFieldEditEngine; + static std::atomic<sc::SharedStringPoolPurge*> pSharedStringPoolPurge; + static void InitPPT(); public: @@ -676,6 +682,8 @@ public: document specific fields, to be used only by ScEditUtil::GetString(). */ static ScFieldEditEngine& GetStaticFieldEditEngine(); + static sc::SharedStringPoolPurge& GetSharedStringPoolPurge(); + /** Replaces the first occurrence of rPlaceholder in rString with rReplacement, or if rPlaceholder is not found appends one space if rString does not end in a space and appends rReplacement. diff --git a/sc/source/core/data/documen2.cxx b/sc/source/core/data/documen2.cxx index dc23b2c3209e..c15d84c5c948 100644 --- a/sc/source/core/data/documen2.cxx +++ b/sc/source/core/data/documen2.cxx @@ -87,6 +87,7 @@ #include <listenercontext.hxx> #include <datamapper.hxx> #include <drwlayer.hxx> +#include <sharedstringpoolpurge.hxx> #include <config_features.h> using namespace com::sun::star; @@ -400,7 +401,14 @@ ScDocument::~ScDocument() mpFormulaGroupCxt.reset(); // Purge unused items if the string pool will be still used (e.g. by undo history). if(mpCellStringPool.use_count() > 1) - mpCellStringPool->purge(); + { + // Calling purge() may be somewhat expensive with large documents, so + // try to delay and compress it for temporary documents. + if(IsClipOrUndo()) + ScGlobal::GetSharedStringPoolPurge().delayedPurge(mpCellStringPool); + else + mpCellStringPool->purge(); + } mpCellStringPool.reset(); assert( pDelayedFormulaGrouping == nullptr ); diff --git a/sc/source/core/data/global.cxx b/sc/source/core/data/global.cxx index e29fccf5c1b2..a42a651cba8e 100644 --- a/sc/source/core/data/global.cxx +++ b/sc/source/core/data/global.cxx @@ -71,6 +71,7 @@ #include <scmod.hxx> #include <editutil.hxx> #include <docsh.hxx> +#include <sharedstringpoolpurge.hxx> tools::SvRef<ScDocShell> ScGlobal::xDrawClipDocShellRef; std::unique_ptr<SvxSearchItem> ScGlobal::xSearchItem; @@ -98,6 +99,7 @@ std::unique_ptr<ScFunctionMgr> ScGlobal::xStarCalcFunctionMgr; std::atomic<ScUnitConverter*> ScGlobal::pUnitConverter(nullptr); std::unique_ptr<SvNumberFormatter> ScGlobal::xEnglishFormatter; std::unique_ptr<ScFieldEditEngine> ScGlobal::xFieldEditEngine; +std::atomic<sc::SharedStringPoolPurge*> ScGlobal::pSharedStringPoolPurge; double ScGlobal::nScreenPPTX = 96.0; double ScGlobal::nScreenPPTY = 96.0; @@ -546,6 +548,7 @@ void ScGlobal::Clear() delete pUnitConverter.exchange(nullptr); xFieldEditEngine.reset(); + delete pSharedStringPoolPurge.exchange(nullptr); xDrawClipDocShellRef.clear(); } @@ -1087,6 +1090,12 @@ ScFieldEditEngine& ScGlobal::GetStaticFieldEditEngine() return *xFieldEditEngine; } +sc::SharedStringPoolPurge& ScGlobal::GetSharedStringPoolPurge() +{ + return *comphelper::doubleCheckedInit( pSharedStringPoolPurge, + []() { return new sc::SharedStringPoolPurge; }); +} + OUString ScGlobal::ReplaceOrAppend( const OUString& rString, std::u16string_view rPlaceholder, const OUString& rReplacement ) { diff --git a/sc/source/core/inc/sharedstringpoolpurge.hxx b/sc/source/core/inc/sharedstringpoolpurge.hxx new file mode 100644 index 000000000000..76ed42b7e47e --- /dev/null +++ b/sc/source/core/inc/sharedstringpoolpurge.hxx @@ -0,0 +1,48 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * 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 <memory> +#include <vector> + +#include <svl/sharedstringpool.hxx> +#include <vcl/timer.hxx> + +namespace svl +{ +class SharedStringPool; +} + +namespace sc +{ +/* +Calls svl::SharedStringPool::purge() after a delay when idle. Can be +used to compress repeated calls, as purge() may be somewhat expensive +with large documents. And since vcl links to svl, it's not possible +to use VCL timers in svl, so a separate class is needed. +*/ +class SharedStringPoolPurge +{ +public: + SharedStringPoolPurge(); + ~SharedStringPoolPurge(); + void delayedPurge(const std::shared_ptr<svl::SharedStringPool>& pool); + +private: + void cleanup(); + std::vector<std::shared_ptr<svl::SharedStringPool>> mPoolsToPurge; + Timer mTimer; + static SharedStringPoolPurge* self; + DECL_LINK(timerHandler, Timer*, void); +}; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/core/tool/sharedstringpoolpurge.cxx b/sc/source/core/tool/sharedstringpoolpurge.cxx new file mode 100644 index 000000000000..7b8749006efc --- /dev/null +++ b/sc/source/core/tool/sharedstringpoolpurge.cxx @@ -0,0 +1,58 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * 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/. + * + */ + +#include <sharedstringpoolpurge.hxx> + +#include <algorithm> + +#include <vcl/svapp.hxx> + +namespace sc +{ +SharedStringPoolPurge::SharedStringPoolPurge() + : mTimer("SharedStringPoolPurge") +{ + mTimer.SetPriority(TaskPriority::LOWEST); + mTimer.SetTimeout(10000); // 10 sec + mTimer.SetInvokeHandler(LINK(this, SharedStringPoolPurge, timerHandler)); +} + +SharedStringPoolPurge::~SharedStringPoolPurge() { cleanup(); } + +void SharedStringPoolPurge::delayedPurge(const std::shared_ptr<svl::SharedStringPool>& pool) +{ + if (std::find(mPoolsToPurge.begin(), mPoolsToPurge.end(), pool) == mPoolsToPurge.end()) + { + mPoolsToPurge.push_back(pool); + SolarMutexGuard guard; + mTimer.Start(); + } +} + +void SharedStringPoolPurge::cleanup() +{ + for (std::shared_ptr<svl::SharedStringPool>& pool : mPoolsToPurge) + { + if (pool.use_count() > 1) + pool->purge(); + } + mPoolsToPurge.clear(); +} + +IMPL_LINK_NOARG(SharedStringPoolPurge, timerHandler, Timer*, void) +{ + SolarMutexGuard guard; + mTimer.Stop(); + cleanup(); +} + +} // namespace + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */