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 <Armin.Le.Grand@me.com>
Tested-by: Jenkins
This commit is contained in:
Armin Le Grand (allotropia)
2024-04-23 09:39:47 +02:00
committed by Armin Le Grand
parent a29d91ac40
commit fd2aaac247
3 changed files with 56 additions and 0 deletions
+1
View File
@@ -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
+54
View File
@@ -49,9 +49,26 @@ size_t getUsedSfxItemSetCount() { return nUsedSfxItemSetCount; }
size_t getAllocatedSfxPoolItemHolderCount() { return nAllocatedSfxPoolItemHolderCount; }
size_t getUsedSfxPoolItemHolderCount() { return nUsedSfxPoolItemHolderCount; }
// <WhichID, <number of entries, typeid_name>>
typedef std::unordered_map<sal_uInt16, std::pair<sal_uInt32, const char*>> HightestUsage;
static HightestUsage aHightestUsage;
// <TotalCount, <number of entries, sum of used count>>
typedef std::unordered_map<sal_uInt16, std::pair<sal_uInt32, sal_uInt32>> 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<sorted> 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<double>(rEntry.nAllUsedCount) / static_cast<double>(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<double>(nUsed) / static_cast<double>(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
+1
View File
@@ -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
}