summaryrefslogtreecommitdiff
path: root/svl
diff options
context:
space:
mode:
authorArmin Le Grand (allotropia) <armin.le.grand.extern@allotropia.de>2024-01-23 20:56:17 +0100
committerArmin Le Grand <Armin.Le.Grand@me.com>2024-01-24 14:27:56 +0100
commit64503f9187252c7ebf85832cca65c0642013bc38 (patch)
treea822786391adf84259406afa0d41ec8b6527d531 /svl
parent2863329783e6507af4cbac796b5b3767f277d75d (diff)
ITEM: Add some default global sharing
As addition to tdf#158605 I have added a global default mechanism to support global sharing of Item instances. It's automated and complements the existing one, see one of the last commits. All in all there are now the following possibilities to support this for individual Item derivations: (1) Do nothing: In that case, if the Item is shareable, the new mechanism will kick in: It will start sharing the Item globally, but not immediately: After a defined amount of allowed non-shared ocurrences (look for NUMBER_OF_UNSHARED_INSTANCES) an instance of the default ItemInstanceManager, a DefaultItemInstanceManager, will be incarnated and used. NOTE: Mixing shared/unshared instances is not a problem (we might even implement a kind of 're-hash' when this kicks in, but is not really needded). (2) Overload getItemInstanceManager for SfxPoolItem in a class derived from SfxPoolItem and... (2a) Return a static incarnation of DefaultItemInstanceManager to immediately start global sharing of that Item derivation. (2b) Implement and return your own implementation and static incarnation of ItemInstanceManager to do something better/ faster that the default implementation can# do. Example: SvxFontItem, uses hashing. The NUMBER_OF_UNSHARED_INSTANCES is currently at (50) which gives a decent relationship bewteen no global sharing (speed) and memory needs. Not sharing is faster (that access to 'find' an equal item is spared which might be costly), sharing again needs less memory. There are two supported ENVVARs to use: (a) SVL_DISABLE_ITEM_INSTANCE_MANAGER: This disables the mechanism of global Item sharing completely. This can be used to test/ check speed/memory needs compared with using it, but also may come in handy to check if evtl. errors/resgrressions have to do with it. (b) SVL_SHARE_ITEMS_GLOBALLY_INSTANTLY: This internally forces the NUMBER_OF_UNSHARED_INSTANCES to be ignored and start sharing ALL Item derivations instantly. Change-Id: I40d9c5f228f0bcbf239f2ce0a02d423054240570 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/162478 Tested-by: Jenkins Reviewed-by: Armin Le Grand <Armin.Le.Grand@me.com>
Diffstat (limited to 'svl')
-rw-r--r--svl/source/items/itemset.cxx151
1 files changed, 127 insertions, 24 deletions
diff --git a/svl/source/items/itemset.cxx b/svl/source/items/itemset.cxx
index df46011dc2d9..907daa23180f 100644
--- a/svl/source/items/itemset.cxx
+++ b/svl/source/items/itemset.cxx
@@ -34,10 +34,11 @@
#include <svl/setitem.hxx>
#include <svl/whiter.hxx>
#include <svl/voiditem.hxx>
-
#include <items_helper.hxx>
static bool g_bDisableItemInstanceManager(getenv("SVL_DISABLE_ITEM_INSTANCE_MANAGER"));
+static bool g_bShareImmediately(getenv("SVL_SHARE_ITEMS_GLOBALLY_INSTANTLY"));
+#define NUMBER_OF_UNSHARED_INSTANCES (50)
#ifdef DBG_UTIL
static size_t nAllocatedSfxItemSetCount(0);
@@ -323,6 +324,116 @@ SfxItemSet::SfxItemSet(SfxItemPool& pool, WhichRangesContainer wids)
assert(svl::detail::validRanges2(m_pWhichRanges));
}
+class InstanceManagerHelper
+{
+ typedef std::unordered_map<std::size_t, std::pair<sal_uInt16, DefaultItemInstanceManager*>> managerTypeMap;
+ managerTypeMap maManagerPerType;
+
+public:
+ InstanceManagerHelper() {}
+ ~InstanceManagerHelper()
+ {
+ for (auto& rCandidate : maManagerPerType)
+ if (nullptr != rCandidate.second.second)
+ delete rCandidate.second.second;
+ }
+
+ ItemInstanceManager* getOrCreateItemInstanceManager(const SfxPoolItem& rItem)
+ {
+ // deactivated?
+ if (g_bDisableItemInstanceManager)
+ return nullptr;
+
+ // Item cannot be shared?
+ if (!rItem.isShareable())
+ return nullptr;
+
+ // prefer getting an ItemInstanceManager directly from
+ // the Item: These are the extra implemented (and thus
+ // hopefully fast) incarnations
+ ItemInstanceManager* pManager(rItem.getItemInstanceManager());
+ if (nullptr != pManager)
+ return pManager;
+
+ // get hash and check memory for existing entry
+ const std::size_t aHash(typeid(rItem).hash_code());
+ managerTypeMap::iterator aHit(maManagerPerType.find(aHash));
+
+ // no instance yet, create one to start usage-counting
+ if (aHit == maManagerPerType.end())
+ {
+ if (g_bShareImmediately)
+ {
+ // create and immediately start sharing
+ DefaultItemInstanceManager* pNew(new DefaultItemInstanceManager);
+ maManagerPerType.insert({aHash, std::make_pair(0, pNew)});
+ return pNew;
+ }
+
+ // start countown from NUMBER_OF_UNSHARED_INSTANCES until zero is reached
+ maManagerPerType.insert({aHash, std::make_pair(NUMBER_OF_UNSHARED_INSTANCES, nullptr)});
+ return nullptr;
+ }
+
+ // if there is already a ItemInstanceManager incarnated, return it
+ if (nullptr != aHit->second.second)
+ return aHit->second.second;
+
+ if (aHit->second.first > 0)
+ {
+ // still not the neeed number of hits, countdown & return nullptr
+ aHit->second.first--;
+ return nullptr;
+ }
+
+ // here there is not yet a ItemInstanceManager incarnated. Do
+ // so and return it
+ assert(nullptr == aHit->second.second);
+ DefaultItemInstanceManager* pNew(new DefaultItemInstanceManager);
+ aHit->second.second = pNew;
+
+ return pNew;
+ }
+
+ ItemInstanceManager* getExistingItemInstanceManager(const SfxPoolItem& rItem)
+ {
+ // deactivated?
+ if (g_bDisableItemInstanceManager)
+ return nullptr;
+
+ // Item cannot be shared?
+ if (!rItem.isShareable())
+ return nullptr;
+
+ // prefer getting an ItemInstanceManager directly from
+ // the Item: These are the extra implemented (and thus
+ // hopefully fast) incarnations
+ ItemInstanceManager* pManager(rItem.getItemInstanceManager());
+ if (nullptr != pManager)
+ return pManager;
+
+ // get hash and check memory for existing entry
+ const std::size_t aHash(typeid(rItem).hash_code());
+ managerTypeMap::iterator aHit(maManagerPerType.find(aHash));
+
+ if (aHit == maManagerPerType.end())
+ // no instance yet, return nullptr
+ return nullptr;
+
+ // if there is already a ItemInstanceManager incarnated, return it
+ if (nullptr != aHit->second.second)
+ return aHit->second.second;
+
+ // count-up neeed number of hits again if item is released
+ if (aHit->second.first < NUMBER_OF_UNSHARED_INSTANCES)
+ aHit->second.first++;
+
+ return nullptr;
+ }
+};
+
+static InstanceManagerHelper aInstanceManagerHelper;
+
SfxPoolItem const* implCreateItemEntry(SfxItemPool& rPool, SfxPoolItem const* pSource, bool bPassingOwnership)
{
if (nullptr == pSource)
@@ -450,18 +561,15 @@ SfxPoolItem const* implCreateItemEntry(SfxItemPool& rPool, SfxPoolItem const* pS
return pSource;
}
- // check if we can globally share the Item using the
- // ItemInstanceManager (only for shareable Items)
- while (!g_bDisableItemInstanceManager && pSource->isShareable())
- {
- ItemInstanceManager* pManager(pSource->getItemInstanceManager());
- if (nullptr == pManager)
- // not supported by this Item, done
- break;
+ // try to get an ItemInstanceManager for global Item instance sharing
+ ItemInstanceManager* pManager(aInstanceManagerHelper.getOrCreateItemInstanceManager(*pSource));
+ // check if we can globally share the Item using an ItemInstanceManager
+ while (nullptr != pManager)
+ {
const SfxPoolItem* pAlternative(pManager->find(*pSource));
if(nullptr == pAlternative)
- // none found, done
+ // no already globally shared one found, done
break;
// need to delete evtl. handed over ownership change Item
@@ -501,12 +609,8 @@ SfxPoolItem const* implCreateItemEntry(SfxItemPool& rPool, SfxPoolItem const* pS
// check if we should register this Item for the global
// ItemInstanceManager mechanism (only for shareable Items)
- if (!g_bDisableItemInstanceManager && pSource->isShareable())
- {
- ItemInstanceManager* pManager(pSource->getItemInstanceManager());
- if (nullptr != pManager)
- pManager->add(*pSource);
- }
+ if (nullptr != pManager)
+ pManager->add(*pSource);
return pSource;
}
@@ -546,14 +650,13 @@ void implCleanupItemEntry(SfxPoolItem const* pSource)
// default items (static and dynamic) are owned by the pool, do not delete
return;
- // check if we should remove this Item from the global
- // ItemInstanceManager mechanism (only for shareable Items)
- if (!g_bDisableItemInstanceManager && pSource->isShareable())
- {
- ItemInstanceManager* pManager(pSource->getItemInstanceManager());
- if (nullptr != pManager)
- pManager->remove(*pSource);
- }
+ // try to get an ItemInstanceManager for global Item instance sharing
+ ItemInstanceManager* pManager(aInstanceManagerHelper.getExistingItemInstanceManager(*pSource));
+
+ // check if we should/can remove this Item from the global
+ // ItemInstanceManager mechanism
+ if (nullptr != pManager)
+ pManager->remove(*pSource);
// decrease RefCnt before deleting (destructor asserts for it and that's
// good to find other errors)