summaryrefslogtreecommitdiff
path: root/comphelper
diff options
context:
space:
mode:
authorLuboš Luňák <l.lunak@collabora.com>2022-02-28 13:01:16 +0100
committerLuboš Luňák <l.lunak@collabora.com>2022-03-07 15:37:41 +0100
commit7df433cdc33b4d6ba38eafad9282d015571433ef (patch)
tree7e098ccb8b54b83cfa33d774f8cbe5b95cbd884a /comphelper
parent4256c764aee0777770466115a97420d9b55c23ac (diff)
optimize ConfigurationProperty::get()
E.g. officecfg::Office::Common::Save::ODF::DefaultVersion::get() gets called quite often during ODS export, taking ~14% of total CPU time, ~%5 in comphelper::getProcessComponentContext (handled by previous commit) and the rest trying to read the property. But it's possible to cache the final property values if there's a notifier that clears the cache on any configuration change (it can't be hidden as a static in the file like the other data becase that way it'd get destroyed too late and crash). This gets it to ~3%, most of which is spent in computing the path hash (which could be presumably made const if the OUString hash function were constexpr). Change-Id: I29f3cefc8442716403d4df8bdf253f4fe847a09c Reviewed-on: https://gerrit.libreoffice.org/c/core/+/130705 Tested-by: Jenkins Reviewed-by: Luboš Luňák <l.lunak@collabora.com>
Diffstat (limited to 'comphelper')
-rw-r--r--comphelper/source/misc/configuration.cxx90
1 files changed, 70 insertions, 20 deletions
diff --git a/comphelper/source/misc/configuration.cxx b/comphelper/source/misc/configuration.cxx
index 46ac8ab6c407..11c3f97ad1cd 100644
--- a/comphelper/source/misc/configuration.cxx
+++ b/comphelper/source/misc/configuration.cxx
@@ -10,11 +10,11 @@
#include <sal/config.h>
#include <cassert>
-#include <map>
-#include <memory>
#include <mutex>
#include <string_view>
+#include <unordered_map>
+#include <com/sun/star/beans/NamedValue.hpp>
#include <com/sun/star/beans/PropertyAttribute.hpp>
#include <com/sun/star/configuration/ReadOnlyAccess.hpp>
#include <com/sun/star/configuration/ReadWriteAccess.hpp>
@@ -27,9 +27,12 @@
#include <com/sun/star/lang/XLocalizable.hpp>
#include <com/sun/star/uno/Any.hxx>
#include <com/sun/star/uno/Reference.hxx>
+#include <com/sun/star/util/XChangesListener.hpp>
+#include <com/sun/star/util/XChangesNotifier.hpp>
#include <comphelper/solarmutex.hxx>
#include <comphelper/configuration.hxx>
#include <comphelper/configurationlistener.hxx>
+#include <cppuhelper/implbase.hxx>
#include <rtl/ustring.hxx>
#include <sal/log.hxx>
#include <i18nlangtag/languagetag.hxx>
@@ -111,13 +114,67 @@ comphelper::detail::ConfigurationWrapper::get()
return GetTheConfigurationWrapper();
}
+namespace
+{
+std::mutex gMutex;
+std::unordered_map<OUString, css::uno::Any> gPropertyCache;
+css::uno::Reference< css::util::XChangesNotifier > gNotifier;
+css::uno::Reference< css::util::XChangesListener > gListener;
+
+class ConfigurationChangesListener
+ : public ::cppu::WeakImplHelper<css::util::XChangesListener>
+{
+public:
+ ConfigurationChangesListener()
+ {}
+ // util::XChangesListener
+ virtual void SAL_CALL changesOccurred( const css::util::ChangesEvent& ) override
+ {
+ std::scoped_lock aGuard(gMutex);
+ gPropertyCache.clear();
+ }
+ virtual void SAL_CALL disposing(const css::lang::EventObject&) override {}
+};
+
+} // namespace
+
comphelper::detail::ConfigurationWrapper::ConfigurationWrapper(
css::uno::Reference< css::uno::XComponentContext > const & context):
context_(context),
access_(css::configuration::ReadWriteAccess::create(context, "*"))
-{}
+{
+ // Set up a configuration notifier to invalidate the cache as needed.
+ try
+ {
+ css::uno::Reference< css::lang::XMultiServiceFactory > xConfigProvider(
+ css::configuration::theDefaultProvider::get( context ) );
+
+ // set root path
+ css::uno::Sequence< css::uno::Any > params {
+ css::uno::makeAny( css::beans::NamedValue{ "nodepath", css::uno::makeAny( OUString("/"))} ),
+ css::uno::makeAny( css::beans::NamedValue{ "locale", css::uno::makeAny( OUString("*"))} ) };
+
+ css::uno::Reference< css::uno::XInterface > xCfg
+ = xConfigProvider->createInstanceWithArguments(u"com.sun.star.configuration.ConfigurationAccess",
+ params);
+
+ gNotifier = css::uno::Reference< css::util::XChangesNotifier >(xCfg, css::uno::UNO_QUERY);
+ assert(gNotifier.is());
+ gListener = css::uno::Reference< ConfigurationChangesListener >(new ConfigurationChangesListener());
+ gNotifier->addChangesListener(gListener);
+ }
+ catch(const css::uno::Exception&)
+ {
+ assert(false);
+ }
+}
-comphelper::detail::ConfigurationWrapper::~ConfigurationWrapper() {}
+comphelper::detail::ConfigurationWrapper::~ConfigurationWrapper()
+{
+ gPropertyCache.clear();
+ gNotifier.clear();
+ gListener.clear();
+}
bool comphelper::detail::ConfigurationWrapper::isReadOnly(OUString const & path)
const
@@ -130,29 +187,22 @@ bool comphelper::detail::ConfigurationWrapper::isReadOnly(OUString const & path)
css::uno::Any comphelper::detail::ConfigurationWrapper::getPropertyValue(OUString const& path) const
{
+ std::scoped_lock aGuard(gMutex);
// Cache the configuration access, since some of the keys are used in hot code.
- // Note that this cache is only used by the officecfg:: auto-generated code, using it for anything
- // else would be unwise because the cache could end up containing stale entries.
- static std::mutex gMutex;
- static std::map<OUString, css::uno::Reference< css::container::XNameAccess >> gAccessMap;
+ auto it = gPropertyCache.find(path);
+ if( it != gPropertyCache.end())
+ return it->second;
sal_Int32 idx = path.lastIndexOf("/");
assert(idx!=-1);
OUString parentPath = path.copy(0, idx);
OUString childName = path.copy(idx+1);
- std::scoped_lock aGuard(gMutex);
-
- // check cache
- auto it = gAccessMap.find(parentPath);
- if (it == gAccessMap.end())
- {
- // not in the cache, look it up
- css::uno::Reference<css::container::XNameAccess> access(
- access_->getByHierarchicalName(parentPath), css::uno::UNO_QUERY_THROW);
- it = gAccessMap.emplace(parentPath, access).first;
- }
- return it->second->getByName(childName);
+ css::uno::Reference<css::container::XNameAccess> access(
+ access_->getByHierarchicalName(parentPath), css::uno::UNO_QUERY_THROW);
+ css::uno::Any property = access->getByName(childName);
+ gPropertyCache.emplace(path, property);
+ return property;
}
void comphelper::detail::ConfigurationWrapper::setPropertyValue(