This MR contains an attempt to work around the limitations we have to deal with when using
TRef objects in massively multithreaded environments (c.f. https://root-forum.cern.ch/t/copying-trefs-and-accessing-tref-data-from-multiple-threads/29417/13).
The idea is relatively straightforward: we introduce a wrapper class which holds both the
TRef object and an actual pointer. Whenever accessing the object we just return the pointer instead of querying the
TRef object. The latter is only updated via contructor,
set() member or the copy constructor used to store and load these objects to/from ROOT files. The pointer is stored via
uintptr_t type because ROOT's IO facilities do not seem to be capable of storing raw pointers to file.
This principle works fine and it has been demonstrated that in a "manual" approach (i.e. only loading/storing the
TRef object with additional function calls when writing/reading to/from file) this works perfectly fine and scales without problem to 96 cores (tested on 2x AMD EPYC 7402). It however is not very nice from a usability perspective: analysis scripts would have to call the (non-intuitive)
loadHistory() function when reading trees from file in order to be able to access the object history. Therefore this MR tries to integrate this behavior by overloading the copy constructor to avoid having to call additional member functions manually. However, only similar performance to the original code just using
TRefs is achieved and I still have to understand why.
@kwolters ideas and/or comments would be very welcome.
The current code base contains some
cout statements to better understand the lifetime of
Objects, for performance measurements these should of course be removed.