diff options
author | Armin Le Grand (allotropia) <armin.le.grand.extern@allotropia.de> | 2024-01-23 20:56:17 +0100 |
---|---|---|
committer | Armin Le Grand <Armin.Le.Grand@me.com> | 2024-01-24 14:27:56 +0100 |
commit | 64503f9187252c7ebf85832cca65c0642013bc38 (patch) | |
tree | a822786391adf84259406afa0d41ec8b6527d531 /svl | |
parent | 2863329783e6507af4cbac796b5b3767f277d75d (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.cxx | 151 |
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) |