Skip to content
Snippets Groups Projects
Commit 6587b658 authored by Philippe Canal's avatar Philippe Canal
Browse files

TIsAProxy retain last 8 matches (rather than 1).

This allows to significant reduce the number of search through the list of cached result ...
That search was a noticeable cause of slow down with an increase of number threads due to the contention
on updating the number of readers (used for the local read/write lock mechanism).
parent d519905b
No related branches found
No related tags found
No related merge requests found
......@@ -28,14 +28,22 @@ class TIsAProxy : public TVirtualIsAProxy {
private:
template <typename T> using Atomic_t = std::atomic<T>;
// On testing with the data from the 250202_181_RECO.root and doing "just" serializing
// the value 8 was the sweet spot of performance. With more slots, too much time is
// spent scanning the array of "last" seen and with less slots then the
// serialization induced by and/or the cost of executed `++fSubTypesReaders is slow
// down (noticeably) the streaming of branches with polymorphic containers.
static constexpr UInt_t fgMaxLastSlot = 8;
const std::type_info *fType; //Actual typeid of the proxy
Atomic_t<TClass*> fClass; //Actual TClass
Atomic_t<void*> fLast; //points into fSubTypes map for last used values
Char_t fSubTypes[72];//map of known sub-types
mutable Atomic_t<UInt_t> fSubTypesReaders; //number of readers of fSubTypes
Atomic_t<Bool_t> fSubTypesWriteLockTaken; //True if there is a writer
Bool_t fVirtual; //Flag if class is virtual
Atomic_t<Bool_t> fInit; //Initialization flag
Atomic_t<void*> fLasts[fgMaxLastSlot]; // points into fSubTypes map for last used values
Atomic_t<UChar_t> fNextLastSlot;// Next slot in fLasts to use for update (ring buffer)
void* FindSubType(const std::type_info*) const;
void* CacheSubType(const std::type_info*, TClass*);
......
......@@ -39,19 +39,22 @@ namespace {
{
return (ClassMap_t::value_type*)p;
}
}
////////////////////////////////////////////////////////////////////////////////
/// Standard initializing constructor
TIsAProxy::TIsAProxy(const std::type_info& typ)
: fType(&typ), fClass(nullptr), fLast(nullptr),
: fType(&typ), fClass(nullptr),
fSubTypesReaders(0), fSubTypesWriteLockTaken(kFALSE),
fVirtual(kFALSE), fInit(kFALSE)
{
static_assert(sizeof(ClassMap_t)<=sizeof(fSubTypes), "ClassMap size is to large for array");
::new(fSubTypes) ClassMap_t();
for(auto& slot : fLasts)
slot = nullptr;
}
////////////////////////////////////////////////////////////////////////////////
......@@ -72,7 +75,8 @@ void TIsAProxy::SetClass(TClass *cl)
{
GetMap(fSubTypes)->clear();
fClass = cl;
fLast = nullptr;
for(auto& slot : fLasts)
slot = nullptr;
}
////////////////////////////////////////////////////////////////////////////////
......@@ -106,20 +110,30 @@ TClass* TIsAProxy::operator()(const void *obj)
if ( typ == fType ) {
return fClass.load();
}
auto last = ToPair(fLast.load());
if ( last && typ == last->first ) {
return last->second;
for(auto& slot : fLasts) {
auto last = ToPair(slot);
if ( last && typ == last->first ) {
return last->second;
}
}
// Check if type is already in sub-class cache
last = ToPair(FindSubType(typ));
auto last = ToPair(FindSubType(typ));
if ( last == nullptr || last->second == nullptr ) {
// Last resort: lookup root class
auto cls = TClass::GetClass(*typ);
last = ToPair(CacheSubType(typ,cls));
}
fLast.store(last);
return last == nullptr? nullptr: last->second;
UChar_t next = fNextLastSlot++;
if (next >= fgMaxLastSlot) {
UChar_t expected_value = next + 1;
next = next % fgMaxLastSlot;
fNextLastSlot.compare_exchange_strong(expected_value, next + 1);
}
fLasts[next].store(last);
return last == nullptr ? nullptr: last->second;
}
////////////////////////////////////////////////////////////////////////////////
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment