Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
RTreeColumnReader.hxx
Go to the documentation of this file.
1// Author: Enrico Guiraud CERN 09/2020
2
3/*************************************************************************
4 * Copyright (C) 1995-2020, Rene Brun and Fons Rademakers. *
5 * All rights reserved. *
6 * *
7 * For the licensing terms see $ROOTSYS/LICENSE. *
8 * For the list of contributors see $ROOTSYS/README/CREDITS. *
9 *************************************************************************/
10
11#ifndef ROOT_RDF_RTREECOLUMNREADER
12#define ROOT_RDF_RTREECOLUMNREADER
13
14#include "RColumnReaderBase.hxx"
15#include <ROOT/RMakeUnique.hxx>
16#include <ROOT/RVec.hxx>
17#include <Rtypes.h> // Long64_t, R__CLING_PTRCHECK
18#include <TTreeReader.h>
19#include <TTreeReaderValue.h>
20#include <TTreeReaderArray.h>
21
22#include <memory>
23#include <string>
24
25namespace ROOT {
26namespace Internal {
27namespace RDF {
28
29/// RTreeColumnReader specialization for TTree values read via TTreeReaderValues
30template <typename T>
31class R__CLING_PTRCHECK(off) RTreeColumnReader final : public ROOT::Detail::RDF::RColumnReaderBase {
32 std::unique_ptr<TTreeReaderValue<T>> fTreeValue;
33
34 void *GetImpl(Long64_t) final { return fTreeValue->Get(); }
35public:
36 /// Construct the RTreeColumnReader. Actual initialization is performed lazily by the Init method.
37 RTreeColumnReader(TTreeReader &r, const std::string &colName)
38 : fTreeValue(std::make_unique<TTreeReaderValue<T>>(r, colName.c_str()))
39 {
40 }
41
42 /// The dtor resets the TTreeReaderValue object.
43 //
44 // Otherwise a race condition is present in which a TTreeReader
45 // and its TTreeReader{Value,Array}s can be deleted concurrently:
46 // - Thread #1) a task ends and pushes back processing slot
47 // - Thread #2) a task starts and overwrites thread-local TTreeReaderValues
48 // - Thread #1) first task deletes TTreeReader
49 // See https://github.com/root-project/root/commit/26e8ace6e47de6794ac9ec770c3bbff9b7f2e945
50 ~RTreeColumnReader() { fTreeValue.reset(); }
51};
52
53/// RTreeColumnReader specialization for TTree values read via TTreeReaderArrays.
54///
55/// TTreeReaderArrays are used whenever the RDF column type is RVec<T>.
56template <typename T>
57class R__CLING_PTRCHECK(off) RTreeColumnReader<RVec<T>> final : public ROOT::Detail::RDF::RColumnReaderBase {
58 std::unique_ptr<TTreeReaderArray<T>> fTreeArray;
59
60 /// Enumerator for the memory layout of the branch
61 enum class EStorageType : char { kContiguous, kUnknown, kSparse };
62
63 /// We return a reference to this RVec to clients, to guarantee a stable address and contiguous memory layout.
65
66 /// Signal whether we ever checked that the branch we are reading with a TTreeReaderArray stores array elements
67 /// in contiguous memory.
68 EStorageType fStorageType = EStorageType::kUnknown;
69
70 /// Whether we already printed a warning about performing a copy of the TTreeReaderArray contents
71 bool fCopyWarningPrinted = false;
72
73 void *GetImpl(Long64_t) final
74 {
75 auto &readerArray = *fTreeArray;
76 // We only use TTreeReaderArrays to read columns that users flagged as type `RVec`, so we need to check
77 // that the branch stores the array as contiguous memory that we can actually wrap in an `RVec`.
78 // Currently we need the first entry to have been loaded to perform the check
79 // TODO Move check to constructor once ROOT-10823 is fixed and TTreeReaderArray itself exposes this information
80 const auto arrSize = readerArray.GetSize();
81 if (EStorageType::kUnknown == fStorageType && arrSize > 1) {
82 // We can decide since the array is long enough
83 fStorageType = EStorageType::kContiguous;
84 for (auto i = 0u; i < arrSize - 1; ++i) {
85 if ((char *)&readerArray[i + 1] - (char *)&readerArray[i] != sizeof(T)) {
86 fStorageType = EStorageType::kSparse;
87 break;
88 }
89 }
90 }
91
92 const auto readerArraySize = readerArray.GetSize();
93 if (EStorageType::kContiguous == fStorageType ||
94 (EStorageType::kUnknown == fStorageType && readerArray.GetSize() < 2)) {
95 if (readerArraySize > 0) {
96 // trigger loading of the contents of the TTreeReaderArray
97 // the address of the first element in the reader array is not necessarily equal to
98 // the address returned by the GetAddress method
99 auto readerArrayAddr = &readerArray.At(0);
100 RVec<T> rvec(readerArrayAddr, readerArraySize);
101 std::swap(fRVec, rvec);
102 } else {
103 RVec<T> emptyVec{};
104 std::swap(fRVec, emptyVec);
105 }
106 } else {
107 // The storage is not contiguous or we don't know yet: we cannot but copy into the rvec
108#ifndef NDEBUG
109 if (!fCopyWarningPrinted) {
110 Warning("RTreeColumnReader::Get",
111 "Branch %s hangs from a non-split branch. A copy is being performed in order "
112 "to properly read the content.",
113 readerArray.GetBranchName());
114 fCopyWarningPrinted = true;
115 }
116#else
117 (void)fCopyWarningPrinted;
118#endif
119 if (readerArraySize > 0) {
120 RVec<T> rvec(readerArray.begin(), readerArray.end());
121 std::swap(fRVec, rvec);
122 } else {
123 RVec<T> emptyVec{};
124 std::swap(fRVec, emptyVec);
125 }
126 }
127 return &fRVec;
128 }
129
130public:
131 RTreeColumnReader(TTreeReader &r, const std::string &colName)
132 : fTreeArray(std::make_unique<TTreeReaderArray<T>>(r, colName.c_str()))
133 {
134 }
135
136 /// See the other class template specializations for an explanation.
137 ~RTreeColumnReader() { fTreeArray.reset(); }
138};
139
140/// RTreeColumnReader specialization for arrays of boolean values read via TTreeReaderArrays.
141///
142/// TTreeReaderArray<bool> is used whenever the RDF column type is RVec<bool>.
143template <>
144class R__CLING_PTRCHECK(off) RTreeColumnReader<RVec<bool>> final : public ROOT::Detail::RDF::RColumnReaderBase {
145
146 std::unique_ptr<TTreeReaderArray<bool>> fTreeArray;
147
148 /// We return a reference to this RVec to clients, to guarantee a stable address and contiguous memory layout
150
151 // We always copy the contents of TTreeReaderArray<bool> into an RVec<bool> (never take a view into the memory
152 // buffer) because the underlying memory buffer might be the one of a std::vector<bool>, which is not a contiguous
153 // slab of bool values.
154 // Note that this also penalizes the case in which the column type is actually bool[], but the possible performance
155 // gains in this edge case is probably not worth the extra complication required to differentiate the two cases.
156 void *GetImpl(Long64_t) final
157 {
158 auto &readerArray = *fTreeArray;
159 const auto readerArraySize = readerArray.GetSize();
160 if (readerArraySize > 0) {
161 // always perform a copy
162 RVec<bool> rvec(readerArray.begin(), readerArray.end());
163 std::swap(fRVec, rvec);
164 } else {
165 RVec<bool> emptyVec{};
166 std::swap(fRVec, emptyVec);
167 }
168 return &fRVec;
169 }
170
171public:
172 RTreeColumnReader(TTreeReader &r, const std::string &colName)
173 : fTreeArray(std::make_unique<TTreeReaderArray<bool>>(r, colName.c_str()))
174 {
175 }
176
177 /// See the other class template specializations for an explanation.
178 ~RTreeColumnReader() { fTreeArray.reset(); }
179};
180
181} // namespace RDF
182} // namespace Internal
183} // namespace ROOT
184
185#endif
ROOT::R::TRInterface & r
Definition Object.C:4
long long Long64_t
Definition RtypesCore.h:73
void Warning(const char *location, const char *msgfmt,...)
Use this function in warning situations.
Definition TError.cxx:231
@ kUnknown
Definition TStructNode.h:19
typedef void((*Func_t)())
std::unique_ptr< TTreeReaderArray< T > > fTreeArray
RTreeColumnReader(TTreeReader &r, const std::string &colName)
EStorageType
Enumerator for the memory layout of the branch.
~RTreeColumnReader()
See the other class template specializations for an explanation.
RVec< T > fRVec
We return a reference to this RVec to clients, to guarantee a stable address and contiguous memory la...
RVec< bool > fRVec
We return a reference to this RVec to clients, to guarantee a stable address and contiguous memory la...
~RTreeColumnReader()
See the other class template specializations for an explanation.
std::unique_ptr< TTreeReaderArray< bool > > fTreeArray
RTreeColumnReader(TTreeReader &r, const std::string &colName)
RTreeColumnReader specialization for TTree values read via TTreeReaderValues.
RTreeColumnReader(TTreeReader &r, const std::string &colName)
Construct the RTreeColumnReader. Actual initialization is performed lazily by the Init method.
~RTreeColumnReader()
The dtor resets the TTreeReaderValue object.
std::unique_ptr< TTreeReaderValue< T > > fTreeValue
A "std::vector"-like collection of values implementing handy operation to analyse them.
Definition RVec.hxx:296
An interface for reading collections stored in ROOT columnar datasets.
An interface for reading values stored in ROOT columnar datasets.
A simple, robust and fast interface to read values from ROOT columnar datasets such as TTree,...
Definition TTreeReader.h:44
tbb::task_arena is an alias of tbb::interface7::task_arena, which doesn't allow to forward declare tb...