Logo ROOT   6.16/01
Reference Guide
RAction.hxx
Go to the documentation of this file.
1// Author: Enrico Guiraud, Danilo Piparo CERN 09/2018
2
3/*************************************************************************
4 * Copyright (C) 1995-2018, 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_RACTION
12#define ROOT_RACTION
13
16#include "ROOT/RDF/NodesUtils.hxx" // InitRDFValues
17#include "ROOT/RDF/Utils.hxx" // ColumnNames_t
20
21#include <cstddef> // std::size_t
22#include <memory>
23#include <string>
24#include <vector>
25
26namespace ROOT {
27namespace Internal {
28namespace RDF {
29
32
33// fwd declarations for RActionCRTP
34namespace GraphDrawing {
35std::shared_ptr<GraphNode> CreateDefineNode(const std::string &colName, const RDFDetail::RCustomColumnBase *columnPtr);
36bool CheckIfDefaultOrDSColumn(const std::string &name, const std::shared_ptr<RDFDetail::RCustomColumnBase> &column);
37} // ns GraphDrawing
38
39/// Unused, not instantiatable. Only the partial specialization RActionCRTP<RAction<...>> can be used.
40template <typename Dummy>
42 static_assert(sizeof(Dummy) < 0, "The unspecialized version of RActionCRTP should never be instantiated");
43};
44
45/// A type-erasing wrapper around RColumnValue.
46/// Used to reduce compile time by avoiding instantiation of very large tuples and/or (std::get<N>...) fold expressions.
48 std::shared_ptr<void> fPtr; // shared_ptr correctly deletes the type-erased object
49
50public:
51 template <typename T>
52 RTypeErasedColumnValue(std::unique_ptr<RColumnValue<T>> v) : fPtr(std::move(v))
53 {
54 }
55
56 template <typename T>
58 {
59 return std::static_pointer_cast<RColumnValue<T>>(fPtr)->Get(e);
60 }
61
62 template <typename T>
64 {
65 return static_cast<RColumnValue<T> *>(fPtr.get());
66 }
67};
68
69/// This overload is specialized to act on RTypeErasedColumnValues instead of RColumnValues.
70template <std::size_t... S, typename... ColTypes>
71void InitRDFValues(unsigned int slot, std::vector<RTypeErasedColumnValue> &values, TTreeReader *r,
74{
75 std::array<bool, sizeof...(S)> isTmpColumn;
76 for (auto i = 0u; i < isTmpColumn.size(); ++i)
77 isTmpColumn[i] = customCols.HasName(bn.at(i));
78
79 using expander = int[];
80 (void)expander{(values.emplace_back(std::make_unique<RColumnValue<ColTypes>>()), 0)..., 0};
81 (void)expander{(isTmpColumn[S]
82 ? values[S].Cast<ColTypes>()->SetTmpColumn(slot, customCols.GetColumns().at(bn.at(S)).get())
83 : values[S].Cast<ColTypes>()->MakeProxy(r, bn.at(S)),
84 0)...,
85 0};
86}
87
88/// This overload is specialized to act on RTypeErasedColumnValues instead of RColumnValues.
89template <std::size_t... S, typename... ColTypes>
90void ResetRDFValueTuple(std::vector<RTypeErasedColumnValue> &values, std::index_sequence<S...>,
92{
93 using expander = int[];
94 (void)expander{(values[S].Cast<ColTypes>()->Reset(), 0)...};
95}
96
97// fwd decl for RActionCRTP
98template <typename Helper, typename PrevDataFrame, typename ColumnTypes_t>
99class RAction;
100
101/// A common template base class for all RActions. Avoids code repetition for specializations of RActions
102/// for different helpers, implementing all of the common logic.
103template <typename Helper, typename PrevDataFrame, typename ColumnTypes_t>
104class RActionCRTP<RAction<Helper, PrevDataFrame, ColumnTypes_t>> : public RActionBase {
106
107 Helper fHelper;
108 const std::shared_ptr<PrevDataFrame> fPrevDataPtr;
109 PrevDataFrame &fPrevData;
110
111public:
113
114 RActionCRTP(Helper &&h, const ColumnNames_t &bl, std::shared_ptr<PrevDataFrame> pd,
115 const RBookedCustomColumns &customColumns)
116 : RActionBase(pd->GetLoopManagerUnchecked(), bl, customColumns), fHelper(std::forward<Helper>(h)),
117 fPrevDataPtr(std::move(pd)), fPrevData(*fPrevDataPtr) { }
118
119 RActionCRTP(const RActionCRTP &) = delete;
121 // must call Deregister here, before fPrevDataFrame is destroyed,
122 // otherwise if fPrevDataFrame is fLoopManager we get a use after delete
123 ~RActionCRTP() { fLoopManager->Deregister(this); }
124
125 Helper &GetHelper() { return fHelper; }
126
127 void Initialize() final { fHelper.Initialize(); }
128
129 void InitSlot(TTreeReader *r, unsigned int slot) final
130 {
131 for (auto &bookedBranch : GetCustomColumns().GetColumns())
132 bookedBranch.second->InitSlot(r, slot);
133 static_cast<Action_t *>(this)->InitColumnValues(r, slot);
134 fHelper.InitTask(r, slot);
135 }
136
137 void Run(unsigned int slot, Long64_t entry) final
138 {
139 // check if entry passes all filters
140 if (fPrevData.CheckFilters(slot, entry))
141 static_cast<Action_t *>(this)->Exec(slot, entry, TypeInd_t());
142 }
143
144 void TriggerChildrenCount() final { fPrevData.IncrChildrenCount(); }
145
146 void FinalizeSlot(unsigned int slot) final
147 {
148 ClearValueReaders(slot);
149 for (auto &column : GetCustomColumns().GetColumns()) {
150 column.second->ClearValueReaders(slot);
151 }
152 fHelper.CallFinalizeTask(slot);
153 }
154
155 void ClearValueReaders(unsigned int slot) { static_cast<Action_t *>(this)->ResetColumnValues(slot, TypeInd_t()); }
156
157 void Finalize() final
158 {
159 fHelper.Finalize();
160 SetHasRun();
161 }
162
163 std::shared_ptr<RDFGraphDrawing::GraphNode> GetGraph()
164 {
165 auto prevNode = fPrevData.GetGraph();
166 auto prevColumns = prevNode->GetDefinedColumns();
167
168 // Action nodes do not need to ask an helper to create the graph nodes. They are never common nodes between
169 // multiple branches
170 auto thisNode = std::make_shared<RDFGraphDrawing::GraphNode>(fHelper.GetActionName());
171 auto evaluatedNode = thisNode;
172 for (auto &column : GetCustomColumns().GetColumns()) {
173 /* Each column that this node has but the previous hadn't has been defined in between,
174 * so it has to be built and appended. */
175 if (RDFGraphDrawing::CheckIfDefaultOrDSColumn(column.first, column.second))
176 continue;
177 if (std::find(prevColumns.begin(), prevColumns.end(), column.first) == prevColumns.end()) {
178 auto defineNode = RDFGraphDrawing::CreateDefineNode(column.first, column.second.get());
179 evaluatedNode->SetPrevNode(defineNode);
180 evaluatedNode = defineNode;
181 }
182 }
183
184 thisNode->AddDefinedColumns(GetCustomColumns().GetNames());
185 thisNode->SetAction(HasRun());
186 evaluatedNode->SetPrevNode(prevNode);
187 return thisNode;
188 }
189
190 /// This method is invoked to update a partial result during the event loop, right before passing the result to a
191 /// user-defined callback registered via RResultPtr::RegisterCallback
192 void *PartialUpdate(unsigned int slot) final { return PartialUpdateImpl(slot); }
193
194private:
195 // this overload is SFINAE'd out if Helper does not implement `PartialUpdate`
196 // the template parameter is required to defer instantiation of the method to SFINAE time
197 template <typename H = Helper>
198 auto PartialUpdateImpl(unsigned int slot) -> decltype(std::declval<H>().PartialUpdate(slot), (void *)(nullptr))
199 {
200 return &fHelper.PartialUpdate(slot);
201 }
202
203 // this one is always available but has lower precedence thanks to `...`
204 void *PartialUpdateImpl(...) { throw std::runtime_error("This action does not support callbacks!"); }
205};
206
207/// An action node in a RDF computation graph.
208template <typename Helper, typename PrevDataFrame, typename ColumnTypes_t = typename Helper::ColumnTypes_t>
209class RAction final : public RActionCRTP<RAction<Helper, PrevDataFrame, ColumnTypes_t>> {
210 std::vector<RDFValueTuple_t<ColumnTypes_t>> fValues;
211
212public:
214
215 RAction(Helper &&h, const ColumnNames_t &bl, std::shared_ptr<PrevDataFrame> pd,
216 const RBookedCustomColumns &customColumns)
217 : ActionCRTP_t(std::forward<Helper>(h), bl, std::move(pd), customColumns), fValues(GetNSlots()) { }
218
219 void InitColumnValues(TTreeReader *r, unsigned int slot)
220 {
222 typename ActionCRTP_t::TypeInd_t{});
223 }
224
225 template <std::size_t... S>
226 void Exec(unsigned int slot, Long64_t entry, std::index_sequence<S...>)
227 {
228 (void)entry; // avoid bogus 'unused parameter' warning in gcc4.9
229 ActionCRTP_t::GetHelper().Exec(slot, std::get<S>(fValues[slot]).Get(entry)...);
230 }
231
232 template <std::size_t... S>
234 {
236 }
237};
238
239// These specializations let RAction<SnapshotHelper[MT]> type-erase their column values, for (presumably) a small hit in
240// performance (which hopefully be completely swallowed by the cost of I/O during the event loop) and a large,
241// measurable gain in compile time and therefore jitting time.
242// Snapshot is the action that most suffers from long compilation times because it happens to be called with dozens
243// if not with a few hundred template parameters, which pretty much never happens for other actions.
244
245// fwd decl
246template <typename... BranchTypes>
248
249template <typename... BranchTypes>
251
252template <typename PrevDataFrame, typename... ColTypes>
253class RAction<SnapshotHelper<ColTypes...>, PrevDataFrame, ROOT::TypeTraits::TypeList<ColTypes...>> final
254 : public RActionCRTP<RAction<SnapshotHelper<ColTypes...>, PrevDataFrame, ROOT::TypeTraits::TypeList<ColTypes...>>> {
255
257 RActionCRTP<RAction<SnapshotHelper<ColTypes...>, PrevDataFrame, ROOT::TypeTraits::TypeList<ColTypes...>>>;
258 using ColumnTypes_t = typename SnapshotHelper<ColTypes...>::ColumnTypes_t;
259
260 std::vector<std::vector<RTypeErasedColumnValue>> fValues;
261
262public:
263 RAction(SnapshotHelper<ColTypes...> &&h, const ColumnNames_t &bl, std::shared_ptr<PrevDataFrame> pd,
264 const RBookedCustomColumns &customColumns)
265 : ActionCRTP_t(std::forward<SnapshotHelper<ColTypes...>>(h), bl, std::move(pd), customColumns),
267 {
268 }
269
270 void InitColumnValues(TTreeReader *r, unsigned int slot)
271 {
274 }
275
276 template <std::size_t... S>
277 void Exec(unsigned int slot, Long64_t entry, std::index_sequence<S...>)
278 {
279 (void)entry; // avoid bogus 'unused parameter' warning in gcc4.9
280 ActionCRTP_t::GetHelper().Exec(slot, fValues[slot][S].template Get<ColTypes>(entry)...);
281 }
282
283 template <std::size_t... S>
285 {
287 }
288};
289
290// Same exact code as above, but for SnapshotHelperMT. I don't know how to avoid repeating this code
291template <typename PrevDataFrame, typename... ColTypes>
292class RAction<SnapshotHelperMT<ColTypes...>, PrevDataFrame, ROOT::TypeTraits::TypeList<ColTypes...>> final
293 : public RActionCRTP<
294 RAction<SnapshotHelperMT<ColTypes...>, PrevDataFrame, ROOT::TypeTraits::TypeList<ColTypes...>>> {
295
297 RActionCRTP<RAction<SnapshotHelperMT<ColTypes...>, PrevDataFrame, ROOT::TypeTraits::TypeList<ColTypes...>>>;
298 using ColumnTypes_t = typename SnapshotHelperMT<ColTypes...>::ColumnTypes_t;
299
300 std::vector<std::vector<RTypeErasedColumnValue>> fValues;
301
302public:
303 RAction(SnapshotHelperMT<ColTypes...> &&h, const ColumnNames_t &bl, std::shared_ptr<PrevDataFrame> pd,
304 const RBookedCustomColumns &customColumns)
305 : ActionCRTP_t(std::forward<SnapshotHelperMT<ColTypes...>>(h), bl, std::move(pd), customColumns),
307 {
308 }
309
310 void InitColumnValues(TTreeReader *r, unsigned int slot)
311 {
314 }
315
316 template <std::size_t... S>
317 void Exec(unsigned int slot, Long64_t entry, std::index_sequence<S...>)
318 {
319 (void)entry; // avoid bogus 'unused parameter' warning in gcc4.9
320 ActionCRTP_t::GetHelper().Exec(slot, fValues[slot][S].template Get<ColTypes>(entry)...);
321 }
322
323 template <std::size_t... S>
325 {
327 }
328};
329
330} // ns RDF
331} // ns Internal
332} // ns ROOT
333
334#endif // ROOT_RACTION
SVector< double, 2 > v
Definition: Dict.h:5
ROOT::R::TRInterface & r
Definition: Object.C:4
#define h(i)
Definition: RSha256.hxx:106
#define e(i)
Definition: RSha256.hxx:103
long long Long64_t
Definition: RtypesCore.h:69
unsigned long long ULong64_t
Definition: RtypesCore.h:70
typedef void((*Func_t)())
const ColumnNames_t & GetColumnNames() const
Definition: RActionBase.hxx:63
RBookedCustomColumns & GetCustomColumns()
Definition: RActionBase.hxx:64
std::make_index_sequence< ColumnTypes_t::list_size > TypeInd_t
Definition: RAction.hxx:112
void * PartialUpdate(unsigned int slot) final
This method is invoked to update a partial result during the event loop, right before passing the res...
Definition: RAction.hxx:192
RActionCRTP(Helper &&h, const ColumnNames_t &bl, std::shared_ptr< PrevDataFrame > pd, const RBookedCustomColumns &customColumns)
Definition: RAction.hxx:114
auto PartialUpdateImpl(unsigned int slot) -> decltype(std::declval< H >().PartialUpdate(slot),(void *)(nullptr))
Definition: RAction.hxx:198
Unused, not instantiatable. Only the partial specialization RActionCRTP<RAction<.....
Definition: RAction.hxx:41
RAction(SnapshotHelperMT< ColTypes... > &&h, const ColumnNames_t &bl, std::shared_ptr< PrevDataFrame > pd, const RBookedCustomColumns &customColumns)
Definition: RAction.hxx:303
RAction(SnapshotHelper< ColTypes... > &&h, const ColumnNames_t &bl, std::shared_ptr< PrevDataFrame > pd, const RBookedCustomColumns &customColumns)
Definition: RAction.hxx:263
An action node in a RDF computation graph.
Definition: RAction.hxx:209
void InitColumnValues(TTreeReader *r, unsigned int slot)
Definition: RAction.hxx:219
void ResetColumnValues(unsigned int slot, std::index_sequence< S... > s)
Definition: RAction.hxx:233
void Exec(unsigned int slot, Long64_t entry, std::index_sequence< S... >)
Definition: RAction.hxx:226
RAction(Helper &&h, const ColumnNames_t &bl, std::shared_ptr< PrevDataFrame > pd, const RBookedCustomColumns &customColumns)
Definition: RAction.hxx:215
std::vector< RDFValueTuple_t< ColumnTypes_t > > fValues
Definition: RAction.hxx:210
Encapsulates the columns defined by the user.
bool HasName(std::string name) const
Check if the provided name is tracked in the names list.
RCustomColumnBasePtrMap_t GetColumns() const
Returns the list of the pointers to the defined columns.
Helper class that updates and returns TTree branches as well as RDataFrame temporary columns.
A type-erasing wrapper around RColumnValue.
Definition: RAction.hxx:47
RTypeErasedColumnValue(std::unique_ptr< RColumnValue< T > > v)
Definition: RAction.hxx:52
A simple, robust and fast interface to read values from ROOT colmnar datasets such as TTree,...
Definition: TTreeReader.h:44
bool CheckIfDefaultOrDSColumn(const std::string &name, const std::shared_ptr< ROOT::Detail::RDF::RCustomColumnBase > &column)
std::shared_ptr< GraphNode > CreateDefineNode(const std::string &columnName, const ROOT::Detail::RDF::RCustomColumnBase *columnPtr)
void InitRDFValues(unsigned int slot, RDFValueTuple &valueTuple, TTreeReader *r, const ColumnNames_t &bn, const RBookedCustomColumns &customCols, std::index_sequence< S... >)
Initialize a tuple of RColumnValues.
Definition: NodesUtils.hxx:54
unsigned int GetNSlots()
Definition: RDFUtils.cxx:246
void ResetRDFValueTuple(std::vector< RTypeErasedColumnValue > &values, std::index_sequence< S... >, ROOT::TypeTraits::TypeList< ColTypes... >)
This overload is specialized to act on RTypeErasedColumnValues instead of RColumnValues.
Definition: RAction.hxx:90
double T(double x)
Definition: ChebyshevPol.h:34
Namespace for new ROOT classes and functions.
Definition: StringConv.hxx:21
ROOT::Detail::RDF::ColumnNames_t ColumnNames_t
Definition: RDataFrame.cxx:790
RooArgSet S(const RooAbsArg &v1)
static constexpr double s
void forward(const LAYERDATA &prevLayerData, LAYERDATA &currLayerData)
apply the weights (and functions) in forward direction of the DNN
Definition: NeuralNet.icc:544
STL namespace.
std::unique_ptr< T > make_unique(Args &&... args)
Definition: RMakeUnique.hxx:26
make_integer_sequence< size_t, _Np > make_index_sequence
Lightweight storage for a collection of types.
Definition: TypeTraits.hxx:27