From fd2aaac24712550e4bbd349575192edb56bc94c9 Mon Sep 17 00:00:00 2001 From: "Armin Le Grand (allotropia)" Date: Mon, 22 Apr 2024 15:16:42 +0200 Subject: [PATCH] ITEM: Add measurements for SfxItemSet usages (debug only) I was wondering how much of that arrays of pointers to SfxPoolItems is actually used in the SfxItemSets in real office runtime, so I added code now to measure that. It does use the state of the ItemSet at destruction, so it is possible that items were added/removed which are not covered, but most cases of internal usages do not do that. I then check/sort the collected data at office shutdown, it will be printed as SAL_INFO when svl.items/vcl.items is set, so use this to see the data. This gives info about the average space utilization in different ItemSets with different sizes, also gives an insight about used ItemSet sizes and amount of their usages. Of course results differ from app to app and dependent of what is done with the office, but interestingly when using quite some files opening from all apps it toggles/normalizes to something around 20-25%... Change-Id: I3eb2f0401c39a5bdb5d1d8176e95df07be4c111a Reviewed-on: https://gerrit.libreoffice.org/c/core/+/166455 Reviewed-by: Armin Le Grand Tested-by: Jenkins --- include/svl/itemset.hxx | 1 + svl/source/items/itemset.cxx | 54 ++++++++++++++++++++++++++++++++++++ vcl/source/app/svapp.cxx | 1 + 3 files changed, 56 insertions(+) diff --git a/include/svl/itemset.hxx b/include/svl/itemset.hxx index d2acbc340e4d..21b146ee393e 100644 --- a/include/svl/itemset.hxx +++ b/include/svl/itemset.hxx @@ -37,6 +37,7 @@ SVL_DLLPUBLIC size_t getUsedSfxItemSetCount(); SVL_DLLPUBLIC size_t getAllocatedSfxPoolItemHolderCount(); SVL_DLLPUBLIC size_t getUsedSfxPoolItemHolderCount(); SVL_DLLPUBLIC void listSfxPoolItemsWithHighestUsage(sal_uInt16); +SVL_DLLPUBLIC void listSfxItemSetUsage(); #endif // ItemSet/ItemPool helpers diff --git a/svl/source/items/itemset.cxx b/svl/source/items/itemset.cxx index 61125a351a3d..4b1207a697aa 100644 --- a/svl/source/items/itemset.cxx +++ b/svl/source/items/itemset.cxx @@ -49,9 +49,26 @@ size_t getUsedSfxItemSetCount() { return nUsedSfxItemSetCount; } size_t getAllocatedSfxPoolItemHolderCount() { return nAllocatedSfxPoolItemHolderCount; } size_t getUsedSfxPoolItemHolderCount() { return nUsedSfxPoolItemHolderCount; } +// > typedef std::unordered_map> HightestUsage; static HightestUsage aHightestUsage; +// > +typedef std::unordered_map> ItemArrayUsage; +static ItemArrayUsage aItemArrayUsage; + +static void addArrayUsage(sal_uInt16 nCount, sal_uInt16 nTotalCount) +{ + ItemArrayUsage::iterator aHit(aItemArrayUsage.find(nTotalCount)); + if (aHit == aItemArrayUsage.end()) + { + aItemArrayUsage.insert({nTotalCount, {1, nCount}}); + return; + } + aHit->second.first++; + aHit->second.second += nCount; +} + static void addUsage(const SfxPoolItem& rCandidate) { HightestUsage::iterator aHit(aHightestUsage.find(rCandidate.Which())); @@ -87,6 +104,42 @@ void listSfxPoolItemsWithHighestUsage(sal_uInt16 nNum) break; } } + +SVL_DLLPUBLIC void listSfxItemSetUsage() +{ + struct sorted { + sal_uInt16 nTotalCount; + sal_uInt32 nAppearances; + sal_uInt32 nAllUsedCount; + sorted(sal_uInt16 _nTotalCount, sal_uInt32 _nAppearances, sal_uInt32 _nAllUsedCount) + : nTotalCount(_nTotalCount), nAppearances(_nAppearances), nAllUsedCount(_nAllUsedCount) {} + bool operator<(const sorted& rDesc) const { return nTotalCount > rDesc.nTotalCount; } + }; + std::vector aSorted; + aSorted.reserve(aItemArrayUsage.size()); + for (const auto& rEntry : aItemArrayUsage) + aSorted.emplace_back(rEntry.first, rEntry.second.first, rEntry.second.second); + std::sort(aSorted.begin(), aSorted.end()); + SAL_INFO("svl.items", "ITEM: List of " << aItemArrayUsage.size() << " SfxItemPool TotalCounts with usages:"); + double fAllFillRatePercent(0.0); + sal_uInt32 nUsed(0); + sal_uInt32 nAllocated(0); + for (const auto& rEntry : aSorted) + { + const sal_uInt32 nAllCount(rEntry.nAppearances * rEntry.nTotalCount); + const double fFillRatePercent(0 == nAllCount ? 0.0 : (static_cast(rEntry.nAllUsedCount) / static_cast(nAllCount)) * 100.0); + SAL_INFO("svl.items", + " TotalCount: " << rEntry.nTotalCount + << " Appearances: " << rEntry.nAppearances + << " FillRate(%): " << fFillRatePercent); + fAllFillRatePercent += fFillRatePercent; + nUsed += rEntry.nAllUsedCount; + nAllocated += rEntry.nTotalCount * rEntry.nAppearances; + } + SAL_INFO("svl.items", " Average FillRate(%): " << fAllFillRatePercent / aItemArrayUsage.size()); + SAL_INFO("svl.items", " Used: " << nUsed << " Allocated: " << nAllocated); + SAL_INFO("svl.items", " Average Used/Allocated(%): " << (static_cast(nUsed) / static_cast(nAllocated)) * 100.0); +} #endif // NOTE: Only needed for one Item in SC (see notes below for // ScPatternAttr). Still keep it so that when errors @@ -826,6 +879,7 @@ SfxItemSet::~SfxItemSet() { #ifdef DBG_UTIL nAllocatedSfxItemSetCount--; + addArrayUsage(Count(), TotalCount()); #endif // cleanup items. No std::fill needed, we are done with this ItemSet. // the callback is not set in destructor, so no worries about that diff --git a/vcl/source/app/svapp.cxx b/vcl/source/app/svapp.cxx index 3b150e1bd956..6f3cab0c90ed 100644 --- a/vcl/source/app/svapp.cxx +++ b/vcl/source/app/svapp.cxx @@ -211,6 +211,7 @@ Application::~Application() // List SfxPoolItems with highest RefCounts, these are the best // candidates to add a ItemInstanceManager mechanism listSfxPoolItemsWithHighestUsage(20); + listSfxItemSetUsage(); #endif }