Wrapper class for TRef
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 reinterpret_cast
as 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 TRef
s 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 TRef
s and Object
s, for performance measurements these should of course be removed.