Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
InterfaceUtils.hxx
Go to the documentation of this file.
1// Author: Enrico Guiraud, Danilo Piparo CERN 02/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_RDF_TINTERFACE_UTILS
12#define ROOT_RDF_TINTERFACE_UTILS
13
14#include <ROOT/RDF/RAction.hxx>
16#include <ROOT/RDF/ActionHelpers.hxx> // for BuildAction
19#include <ROOT/RDF/RDefine.hxx>
21#include <ROOT/RDF/RFilter.hxx>
22#include <ROOT/RDF/Utils.hxx>
28#include <string_view>
30#include <ROOT/TypeTraits.hxx>
31#include <TError.h> // gErrorIgnoreLevel
32#include <TH1.h>
33#include <TROOT.h> // IsImplicitMTEnabled
34
35#include <deque>
36#include <functional>
37#include <list>
38#include <memory>
39#include <string>
40#include <type_traits>
41#include <typeinfo>
42#include <vector>
43
44class TTree;
45namespace ROOT {
46namespace Detail {
47namespace RDF {
48class RNodeBase;
49}
50}
51namespace RDF {
52template<typename T, typename V>
53class RInterface;
55} // namespace RDF
56
57} // namespace ROOT
58
59/// \cond HIDDEN_SYMBOLS
60
61namespace ROOT {
62namespace Internal {
63namespace RDF {
64using namespace ROOT::Detail::RDF;
65using namespace ROOT::RDF;
66namespace TTraits = ROOT::TypeTraits;
67
68std::string DemangleTypeIdName(const std::type_info &typeInfo);
69
70ColumnNames_t
71ConvertRegexToColumns(const ColumnNames_t &colNames, std::string_view columnNameRegexp, std::string_view callerName);
72
73/// An helper object that sets and resets gErrorIgnoreLevel via RAII.
75private:
77
78public:
81};
82
83/****** BuildAction overloads *******/
84
85// clang-format off
86/// This namespace defines types to be used for tag dispatching in RInterface.
87namespace ActionTags {
88struct Histo1D{};
89struct Histo2D{};
90struct Histo3D{};
91struct HistoND{};
92struct Graph{};
93struct GraphAsymmErrors{};
94struct Profile1D{};
95struct Profile2D{};
96struct Min{};
97struct Max{};
98struct Sum{};
99struct Mean{};
100struct Fill{};
101struct StdDev{};
102struct Display{};
103struct Snapshot{};
104struct Book{};
105}
106// clang-format on
107
108template <typename T, bool ISV6HISTO = std::is_base_of<TH1, std::decay_t<T>>::value>
109struct HistoUtils {
110 static void SetCanExtendAllAxes(T &h) { h.SetCanExtend(::TH1::kAllAxes); }
111 static bool HasAxisLimits(T &h)
112 {
113 auto xaxis = h.GetXaxis();
114 return !(xaxis->GetXmin() == 0. && xaxis->GetXmax() == 0.);
115 }
116};
117
118template <typename T>
119struct HistoUtils<T, false> {
120 static void SetCanExtendAllAxes(T &) {}
121 static bool HasAxisLimits(T &) { return true; }
122};
123
124// Generic filling (covers Histo2D, HistoND, Profile1D and Profile2D actions, with and without weights)
125template <typename... ColTypes, typename ActionTag, typename ActionResultType, typename PrevNodeType>
126std::unique_ptr<RActionBase>
127BuildAction(const ColumnNames_t &bl, const std::shared_ptr<ActionResultType> &h, const unsigned int nSlots,
128 std::shared_ptr<PrevNodeType> prevNode, ActionTag, const RColumnRegister &colRegister)
129{
131 using Action_t = RAction<Helper_t, PrevNodeType, TTraits::TypeList<ColTypes...>>;
132 return std::make_unique<Action_t>(Helper_t(h, nSlots), bl, std::move(prevNode), colRegister);
133}
134
135// Histo1D filling (must handle the special case of distinguishing FillHelper and BufferedFillHelper
136template <typename... ColTypes, typename PrevNodeType>
137std::unique_ptr<RActionBase>
138BuildAction(const ColumnNames_t &bl, const std::shared_ptr<::TH1D> &h, const unsigned int nSlots,
139 std::shared_ptr<PrevNodeType> prevNode, ActionTags::Histo1D, const RColumnRegister &colRegister)
140{
142
145 using Action_t = RAction<Helper_t, PrevNodeType, TTraits::TypeList<ColTypes...>>;
146 return std::make_unique<Action_t>(Helper_t(h, nSlots), bl, std::move(prevNode), colRegister);
147 } else {
149 using Action_t = RAction<Helper_t, PrevNodeType, TTraits::TypeList<ColTypes...>>;
150 return std::make_unique<Action_t>(Helper_t(h, nSlots), bl, std::move(prevNode), colRegister);
151 }
152}
153
154// Action for Histo3D, where thread safe filling might be supported to save memory
155template <typename... ColTypes, typename ActionResultType, typename PrevNodeType>
156std::unique_ptr<RActionBase>
157BuildAction(const ColumnNames_t &bl, const std::shared_ptr<ActionResultType> &h, const unsigned int nSlots,
158 std::shared_ptr<PrevNodeType> prevNode, ActionTags::Histo3D, const RColumnRegister &colRegister)
159{
160 if (RDFInternal::NThreadPerTH3() <= 1 || nSlots == 1) {
162 using Action_t = RAction<Helper_t, PrevNodeType, TTraits::TypeList<ColTypes...>>;
163 return std::make_unique<Action_t>(Helper_t(h, nSlots), bl, std::move(prevNode), colRegister);
164 } else {
166 using Action_t = RAction<Helper_t, PrevNodeType, TTraits::TypeList<ColTypes...>>;
167 if constexpr (sizeof...(ColTypes) > 3) {
168 h->Sumw2();
169 }
170 const auto histoSlots = std::max(nSlots / RDFInternal::NThreadPerTH3(), 1u);
171 return std::make_unique<Action_t>(Helper_t(h, histoSlots), bl, std::move(prevNode), colRegister);
172 }
173}
174
175template <typename... ColTypes, typename PrevNodeType>
176std::unique_ptr<RActionBase>
177BuildAction(const ColumnNames_t &bl, const std::shared_ptr<TGraph> &g, const unsigned int nSlots,
178 std::shared_ptr<PrevNodeType> prevNode, ActionTags::Graph, const RColumnRegister &colRegister)
179{
181 using Action_t = RAction<Helper_t, PrevNodeType, TTraits::TypeList<ColTypes...>>;
182 return std::make_unique<Action_t>(Helper_t(g, nSlots), bl, std::move(prevNode), colRegister);
183}
184
185template <typename... ColTypes, typename PrevNodeType>
186std::unique_ptr<RActionBase>
187BuildAction(const ColumnNames_t &bl, const std::shared_ptr<TGraphAsymmErrors> &g, const unsigned int nSlots,
188 std::shared_ptr<PrevNodeType> prevNode, ActionTags::GraphAsymmErrors, const RColumnRegister &colRegister)
189{
191 using Action_t = RAction<Helper_t, PrevNodeType, TTraits::TypeList<ColTypes...>>;
192 return std::make_unique<Action_t>(Helper_t(g, nSlots), bl, std::move(prevNode), colRegister);
193}
194
195// Min action
196template <typename ColType, typename PrevNodeType, typename ActionResultType>
197std::unique_ptr<RActionBase>
198BuildAction(const ColumnNames_t &bl, const std::shared_ptr<ActionResultType> &minV, const unsigned int nSlots,
199 std::shared_ptr<PrevNodeType> prevNode, ActionTags::Min, const RColumnRegister &colRegister)
200{
203 return std::make_unique<Action_t>(Helper_t(minV, nSlots), bl, std::move(prevNode), colRegister);
204}
205
206// Max action
207template <typename ColType, typename PrevNodeType, typename ActionResultType>
208std::unique_ptr<RActionBase>
209BuildAction(const ColumnNames_t &bl, const std::shared_ptr<ActionResultType> &maxV, const unsigned int nSlots,
210 std::shared_ptr<PrevNodeType> prevNode, ActionTags::Max, const RColumnRegister &colRegister)
211{
214 return std::make_unique<Action_t>(Helper_t(maxV, nSlots), bl, std::move(prevNode), colRegister);
215}
216
217// Sum action
218template <typename ColType, typename PrevNodeType, typename ActionResultType>
219std::unique_ptr<RActionBase>
220BuildAction(const ColumnNames_t &bl, const std::shared_ptr<ActionResultType> &sumV, const unsigned int nSlots,
221 std::shared_ptr<PrevNodeType> prevNode, ActionTags::Sum, const RColumnRegister &colRegister)
222{
225 return std::make_unique<Action_t>(Helper_t(sumV, nSlots), bl, std::move(prevNode), colRegister);
226}
227
228// Mean action
229template <typename ColType, typename PrevNodeType>
230std::unique_ptr<RActionBase>
231BuildAction(const ColumnNames_t &bl, const std::shared_ptr<double> &meanV, const unsigned int nSlots,
232 std::shared_ptr<PrevNodeType> prevNode, ActionTags::Mean, const RColumnRegister &colRegister)
233{
234 using Helper_t = MeanHelper;
236 return std::make_unique<Action_t>(Helper_t(meanV, nSlots), bl, std::move(prevNode), colRegister);
237}
238
239// Standard Deviation action
240template <typename ColType, typename PrevNodeType>
241std::unique_ptr<RActionBase>
242BuildAction(const ColumnNames_t &bl, const std::shared_ptr<double> &stdDeviationV, const unsigned int nSlots,
243 std::shared_ptr<PrevNodeType> prevNode, ActionTags::StdDev, const RColumnRegister &colRegister)
244{
245 using Helper_t = StdDevHelper;
247 return std::make_unique<Action_t>(Helper_t(stdDeviationV, nSlots), bl, prevNode, colRegister);
248}
249
250using displayHelperArgs_t = std::pair<size_t, std::shared_ptr<ROOT::RDF::RDisplay>>;
251
252// Display action
253template <typename... ColTypes, typename PrevNodeType>
254std::unique_ptr<RActionBase>
255BuildAction(const ColumnNames_t &bl, const std::shared_ptr<displayHelperArgs_t> &helperArgs, const unsigned int,
256 std::shared_ptr<PrevNodeType> prevNode, ActionTags::Display, const RColumnRegister &colRegister)
257{
259 using Action_t = RAction<Helper_t, PrevNodeType, TTraits::TypeList<ColTypes...>>;
260 return std::make_unique<Action_t>(Helper_t(helperArgs->first, helperArgs->second, prevNode), bl, prevNode,
262}
263
264struct SnapshotHelperArgs {
265 std::string fFileName;
266 std::string fDirName;
267 std::string fTreeName;
268 std::vector<std::string> fOutputColNames;
270 ROOT::Detail::RDF::RLoopManager *fOutputLoopManager;
271 ROOT::Detail::RDF::RLoopManager *fInputLoopManager;
272 bool fToNTuple;
273};
274
275template <typename PrevNodeType>
276std::unique_ptr<RActionBase>
277BuildAction(const ColumnNames_t &colNames, const std::shared_ptr<SnapshotHelperArgs> &snapHelperArgs,
278 const unsigned int nSlots, std::shared_ptr<PrevNodeType> prevNode, const RColumnRegister &colRegister,
279 const std::vector<const std::type_info *> &colTypeIDs)
280{
281 const auto &filename = snapHelperArgs->fFileName;
282 const auto &dirname = snapHelperArgs->fDirName;
283 const auto &treename = snapHelperArgs->fTreeName;
284 const auto &outputColNames = snapHelperArgs->fOutputColNames;
285 const auto &options = snapHelperArgs->fOptions;
286 const auto &outputLM = snapHelperArgs->fOutputLoopManager;
287 const auto &inputLM = snapHelperArgs->fInputLoopManager;
288
289 auto sz = colNames.size();
290 std::vector<bool> isDefine(sz);
291 for (auto i = 0u; i < sz; ++i)
292 isDefine[i] = colRegister.IsDefineOrAlias(colNames[i]);
293
294 std::unique_ptr<RActionBase> actionPtr;
295 if (snapHelperArgs->fToNTuple) {
297 // single-thread snapshot
298 using Helper_t = UntypedSnapshotRNTupleHelper;
300
302 outputLM, std::move(isDefine), colTypeIDs),
303 colNames, colTypeIDs, prevNode, colRegister));
304 } else {
305 // multi-thread snapshot to RNTuple is not yet supported
306 // TODO(fdegeus) Add MT snapshotting
307 throw std::runtime_error("Snapshot: Snapshotting to RNTuple with IMT enabled is not supported yet.");
308 }
309 } else {
311 // single-thread snapshot
312 using Helper_t = UntypedSnapshotTTreeHelper;
315 std::move(isDefine), outputLM, inputLM, colTypeIDs),
316 colNames, colTypeIDs, prevNode, colRegister));
317 } else {
318 // multi-thread snapshot
319 using Helper_t = UntypedSnapshotTTreeHelperMT;
322 std::move(isDefine), outputLM, inputLM, colTypeIDs),
323 colNames, colTypeIDs, prevNode, colRegister));
324 }
325 }
326
327 return actionPtr;
328}
329
330// Book with custom helper type
331template <typename... ColTypes, typename PrevNodeType, typename Helper_t>
332std::unique_ptr<RActionBase>
333BuildAction(const ColumnNames_t &bl, const std::shared_ptr<Helper_t> &h, const unsigned int /*nSlots*/,
334 std::shared_ptr<PrevNodeType> prevNode, ActionTags::Book, const RColumnRegister &colRegister)
335{
336 using Action_t = RAction<Helper_t, PrevNodeType, TTraits::TypeList<ColTypes...>>;
337 return std::make_unique<Action_t>(Helper_t(std::move(*h)), bl, std::move(prevNode), colRegister);
338}
339
340/****** end BuildAndBook ******/
341
342template <typename Filter>
343void CheckFilter(Filter &)
344{
345 using FilterRet_t = typename RDF::CallableTraits<Filter>::ret_type;
346 static_assert(std::is_convertible<FilterRet_t, bool>::value,
347 "filter expression returns a type that is not convertible to bool");
348}
349
350ColumnNames_t FilterArraySizeColNames(const ColumnNames_t &columnNames, const std::string &action);
351
352void CheckValidCppVarName(std::string_view var, const std::string &where);
353
354void CheckForRedefinition(const std::string &where, std::string_view definedCol, const RColumnRegister &colRegister,
355 const ColumnNames_t &dataSourceColumns);
356
357void CheckForDefinition(const std::string &where, std::string_view definedColView, const RColumnRegister &colRegister,
358 const ColumnNames_t &dataSourceColumns);
359
360void CheckForNoVariations(const std::string &where, std::string_view definedColView,
361 const RColumnRegister &colRegister);
362
363std::string PrettyPrintAddr(const void *const addr);
364
365std::shared_ptr<RJittedFilter> BookFilterJit(std::shared_ptr<RNodeBase> *prevNodeOnHeap, std::string_view name,
366 std::string_view expression, const RColumnRegister &colRegister,
367 TTree *tree, RDataSource *ds);
368
369std::shared_ptr<RJittedDefine> BookDefineJit(std::string_view name, std::string_view expression, RLoopManager &lm,
370 RDataSource *ds, const RColumnRegister &colRegister,
371 std::shared_ptr<RNodeBase> *prevNodeOnHeap);
372
373std::shared_ptr<RJittedDefine> BookDefinePerSampleJit(std::string_view name, std::string_view expression,
374 RLoopManager &lm, const RColumnRegister &colRegister,
375 std::shared_ptr<RNodeBase> *upcastNodeOnHeap);
376
377std::shared_ptr<RJittedVariation>
378BookVariationJit(const std::vector<std::string> &colNames, std::string_view variationName,
379 const std::vector<std::string> &variationTags, std::string_view expression, RLoopManager &lm,
380 RDataSource *ds, const RColumnRegister &colRegister, std::shared_ptr<RNodeBase> *upcastNodeOnHeap,
381 bool isSingleColumn);
382
383std::string JitBuildAction(const ColumnNames_t &bl, std::shared_ptr<RDFDetail::RNodeBase> *prevNode,
384 const std::type_info &art, const std::type_info &at, void *rOnHeap, TTree *tree,
385 const unsigned int nSlots, const RColumnRegister &colRegister, RDataSource *ds,
386 std::weak_ptr<RJittedAction> *jittedActionOnHeap, const bool vector2RVec = true);
387
388// Allocate a weak_ptr on the heap, return a pointer to it. The user is responsible for deleting this weak_ptr.
389// This function is meant to be used by RInterface's methods that book code for jitting.
390// The problem it solves is that we generate code to be lazily jitted with the addresses of certain objects in them,
391// and we need to check those objects are still alive when the generated code is finally jitted and executed.
392// So we pass addresses to weak_ptrs allocated on the heap to the jitted code, which is then responsible for
393// the deletion of the weak_ptr object.
394template <typename T>
395std::weak_ptr<T> *MakeWeakOnHeap(const std::shared_ptr<T> &shPtr)
396{
397 return new std::weak_ptr<T>(shPtr);
398}
399
400// Same as MakeWeakOnHeap, but create a shared_ptr that makes sure the object is definitely kept alive.
401template <typename T>
402std::shared_ptr<T> *MakeSharedOnHeap(const std::shared_ptr<T> &shPtr)
403{
404 return new std::shared_ptr<T>(shPtr);
405}
406
407bool AtLeastOneEmptyString(const std::vector<std::string_view> strings);
408
409/// Take a shared_ptr<AnyNodeType> and return a shared_ptr<RNodeBase>.
410/// This works for RLoopManager nodes as well as filters and ranges.
411std::shared_ptr<RNodeBase> UpcastNode(std::shared_ptr<RNodeBase> ptr);
412
413ColumnNames_t GetValidatedColumnNames(RLoopManager &lm, const unsigned int nColumns, const ColumnNames_t &columns,
414 const RColumnRegister &validDefines, RDataSource *ds);
415
416std::vector<std::string> GetValidatedArgTypes(const ColumnNames_t &colNames, const RColumnRegister &colRegister,
417 TTree *tree, RDataSource *ds, const std::string &context,
418 bool vector2RVec);
419
420std::vector<bool> FindUndefinedDSColumns(const ColumnNames_t &requestedCols, const ColumnNames_t &definedDSCols);
421
422template <typename T>
423void AddDSColumnsHelper(const std::string &colName, RLoopManager &lm, RDataSource &ds, RColumnRegister &colRegister)
424{
425
426 if (colRegister.IsDefineOrAlias(colName))
427 return;
428
429 if (lm.HasDataSourceColumnReaders(colName, typeid(T)))
430 return;
431
432 if (!ds.HasColumn(colName) &&
433 lm.GetSuppressErrorsForMissingBranches().find(colName) == lm.GetSuppressErrorsForMissingBranches().end())
434 return;
435
436 const auto nSlots = lm.GetNSlots();
437 std::vector<std::unique_ptr<RColumnReaderBase>> colReaders;
438 colReaders.reserve(nSlots);
439
440 const auto valuePtrs = ds.GetColumnReaders<T>(colName);
441 if (!valuePtrs.empty()) { // we are using the old GetColumnReaders mechanism in this RDataSource
442 for (auto *ptr : valuePtrs)
443 colReaders.emplace_back(new RDSColumnReader<T>(ptr));
444
445 } else { // using the new GetColumnReaders mechanism
446 // TODO consider changing the interface so we return all of these for all slots in one go
447 for (auto slot = 0u; slot < lm.GetNSlots(); ++slot)
448 colReaders.emplace_back(
449 ROOT::Internal::RDF::CreateColumnReader(ds, slot, colName, typeid(T), /*treeReader*/ nullptr));
450 }
451
452 lm.AddDataSourceColumnReaders(colName, std::move(colReaders), typeid(T));
453}
454
455/// Take list of column names that must be defined, current map of custom columns, current list of defined column names,
456/// and return a new map of custom columns (with the new datasource columns added to it)
457template <typename... ColumnTypes>
458void AddDSColumns(const std::vector<std::string> &requiredCols, RLoopManager &lm, RDataSource &ds,
460{
461 // hack to expand a template parameter pack without c++17 fold expressions.
462 using expander = int[];
463 int i = 0;
465}
466
467void AddDSColumns(const std::vector<std::string> &requiredCols, ROOT::Detail::RDF::RLoopManager &lm,
468 ROOT::RDF::RDataSource &ds, const std::vector<const std::type_info *> &colTypeIDs,
470
471// this function is meant to be called by the jitted code generated by BookFilterJit
472template <typename F, typename PrevNode>
473void JitFilterHelper(F &&f, const char **colsPtr, std::size_t colsSize, std::string_view name,
474 std::weak_ptr<RJittedFilter> *wkJittedFilter, std::shared_ptr<PrevNode> *prevNodeOnHeap,
475 RColumnRegister *colRegister) noexcept
476{
477 if (wkJittedFilter->expired()) {
478 // The branch of the computation graph that needed this jitted code went out of scope between the type
479 // jitting was booked and the time jitting actually happened. Nothing to do other than cleaning up.
480 delete wkJittedFilter;
481 delete colRegister;
482 delete prevNodeOnHeap;
483 return;
484 }
485
486 const ColumnNames_t cols(colsPtr, colsPtr + colsSize);
487 delete[] colsPtr;
488
489 const auto jittedFilter = wkJittedFilter->lock();
490
491 // mock Filter logic -- validity checks and Define-ition of RDataSource columns
492 using Callable_t = std::decay_t<F>;
494 using ColTypes_t = typename TTraits::CallableTraits<Callable_t>::arg_types;
495 constexpr auto nColumns = ColTypes_t::list_size;
496 CheckFilter(f);
497
498 auto &lm = *jittedFilter->GetLoopManagerUnchecked(); // RLoopManager must exist at this time
499 auto ds = lm.GetDataSource();
500
501 if (ds != nullptr)
503
504 jittedFilter->SetFilter(
505 std::unique_ptr<RFilterBase>(new F_t(std::forward<F>(f), cols, *prevNodeOnHeap, *colRegister, name)));
506 // colRegister points to the columns structure in the heap, created before the jitted call so that the jitter can
507 // share data after it has lazily compiled the code. Here the data has been used and the memory can be freed.
508 delete colRegister;
509 delete prevNodeOnHeap;
510 delete wkJittedFilter;
511}
512
513namespace DefineTypes {
514struct RDefineTag {};
515struct RDefinePerSampleTag {};
516}
517
518template <typename F>
519auto MakeDefineNode(DefineTypes::RDefineTag, std::string_view name, std::string_view dummyType, F &&f,
520 const ColumnNames_t &cols, RColumnRegister &colRegister, RLoopManager &lm)
521{
522 return std::unique_ptr<RDefineBase>(new RDefine<std::decay_t<F>, ExtraArgsForDefine::None>(
523 name, dummyType, std::forward<F>(f), cols, colRegister, lm));
524}
525
526template <typename F>
527auto MakeDefineNode(DefineTypes::RDefinePerSampleTag, std::string_view name, std::string_view dummyType, F &&f,
528 const ColumnNames_t &, RColumnRegister &, RLoopManager &lm)
529{
530 return std::unique_ptr<RDefineBase>(
531 new RDefinePerSample<std::decay_t<F>>(name, dummyType, std::forward<F>(f), lm));
532}
533
534// Build a RDefine or a RDefinePerSample object and attach it to an existing RJittedDefine
535// This function is meant to be called by jitted code right before starting the event loop.
536// If colsPtr is null, build a RDefinePerSample (it has no input columns), otherwise a RDefine.
537template <typename RDefineTypeTag, typename F>
538void JitDefineHelper(F &&f, const char **colsPtr, std::size_t colsSize, std::string_view name, RLoopManager *lm,
539 std::weak_ptr<RJittedDefine> *wkJittedDefine, RColumnRegister *colRegister,
540 std::shared_ptr<RNodeBase> *prevNodeOnHeap) noexcept
541{
542 // a helper to delete objects allocated before jitting, so that the jitter can share data with lazily jitted code
543 auto doDeletes = [&] {
544 delete wkJittedDefine;
545 delete colRegister;
546 delete prevNodeOnHeap;
547 delete[] colsPtr;
548 };
549
550 if (wkJittedDefine->expired()) {
551 // The branch of the computation graph that needed this jitted code went out of scope between the type
552 // jitting was booked and the time jitting actually happened. Nothing to do other than cleaning up.
553 doDeletes();
554 return;
555 }
556
557 const ColumnNames_t cols(colsPtr, colsPtr + colsSize);
558
559 auto jittedDefine = wkJittedDefine->lock();
560
561 using Callable_t = std::decay_t<F>;
562 using ColTypes_t = typename TTraits::CallableTraits<Callable_t>::arg_types;
563
564 auto ds = lm->GetDataSource();
565 if (ds != nullptr && colsPtr)
567
568 // will never actually be used (trumped by jittedDefine->GetTypeName()), but we set it to something meaningful
569 // to help devs debugging
570 const auto dummyType = "jittedCol_t";
571 // use unique_ptr<RDefineBase> instead of make_unique<NewCol_t> to reduce jit/compile-times
572 std::unique_ptr<RDefineBase> newCol{
573 MakeDefineNode(RDefineTypeTag{}, name, dummyType, std::forward<F>(f), cols, *colRegister, *lm)};
574 jittedDefine->SetDefine(std::move(newCol));
575
576 doDeletes();
577}
578
579template <bool IsSingleColumn, typename F>
580void JitVariationHelper(F &&f, const char **colsPtr, std::size_t colsSize, const char **variedCols,
581 std::size_t variedColsSize, const char **variationTags, std::size_t variationTagsSize,
582 std::string_view variationName, RLoopManager *lm,
583 std::weak_ptr<RJittedVariation> *wkJittedVariation, RColumnRegister *colRegister,
584 std::shared_ptr<RNodeBase> *prevNodeOnHeap) noexcept
585{
586 // a helper to delete objects allocated before jitting, so that the jitter can share data with lazily jitted code
587 auto doDeletes = [&] {
588 delete[] colsPtr;
589 delete[] variedCols;
590 delete[] variationTags;
591
592 delete wkJittedVariation;
593 delete colRegister;
594 delete prevNodeOnHeap;
595 };
596
597 if (wkJittedVariation->expired()) {
598 // The branch of the computation graph that needed this jitted variation went out of scope between the type
599 // jitting was booked and the time jitting actually happened. Nothing to do other than cleaning up.
600 doDeletes();
601 return;
602 }
603
604 const ColumnNames_t inputColNames(colsPtr, colsPtr + colsSize);
605 std::vector<std::string> variedColNames(variedCols, variedCols + variedColsSize);
606 std::vector<std::string> tags(variationTags, variationTags + variationTagsSize);
607
608 auto jittedVariation = wkJittedVariation->lock();
609
610 using Callable_t = std::decay_t<F>;
611 using ColTypes_t = typename TTraits::CallableTraits<Callable_t>::arg_types;
612
613 auto ds = lm->GetDataSource();
614 if (ds != nullptr)
616
617 // use unique_ptr<RDefineBase> instead of make_unique<NewCol_t> to reduce jit/compile-times
618 std::unique_ptr<RVariationBase> newVariation{new RVariation<std::decay_t<F>, IsSingleColumn>(
619 std::move(variedColNames), variationName, std::forward<F>(f), std::move(tags), jittedVariation->GetTypeName(),
621 jittedVariation->SetVariation(std::move(newVariation));
622
623 doDeletes();
624}
625
626/// Convenience function invoked by jitted code to build action nodes at runtime
627template <typename ActionTag, typename... ColTypes, typename PrevNodeType, typename HelperArgType>
628void CallBuildAction(std::shared_ptr<PrevNodeType> *prevNodeOnHeap, const char **colsPtr, std::size_t colsSize,
629 const unsigned int nSlots, std::shared_ptr<HelperArgType> *helperArgOnHeap,
630 std::weak_ptr<RJittedAction> *wkJittedActionOnHeap, RColumnRegister *colRegister) noexcept
631{
632 // a helper to delete objects allocated before jitting, so that the jitter can share data with lazily jitted code
633 auto doDeletes = [&] {
634 delete[] colsPtr;
635 delete helperArgOnHeap;
637 // colRegister must be deleted before prevNodeOnHeap because their dtor needs the RLoopManager to be alive
638 // and prevNodeOnHeap is what keeps it alive if the rest of the computation graph is already out of scope
639 delete colRegister;
640 delete prevNodeOnHeap;
641 };
642
643 if (wkJittedActionOnHeap->expired()) {
644 // The branch of the computation graph that needed this jitted variation went out of scope between the type
645 // jitting was booked and the time jitting actually happened. Nothing to do other than cleaning up.
646 doDeletes();
647 return;
648 }
649
650 const ColumnNames_t cols(colsPtr, colsPtr + colsSize);
651
653
654 // if we are here it means we are jitting, if we are jitting the loop manager must be alive
656 auto &loopManager = *prevNodePtr->GetLoopManagerUnchecked();
657 using ColTypes_t = TypeList<ColTypes...>;
658 constexpr auto nColumns = ColTypes_t::list_size;
659 auto ds = loopManager.GetDataSource();
660 if (ds != nullptr)
662
663 auto actionPtr = BuildAction<ColTypes...>(cols, std::move(*helperArgOnHeap), nSlots, std::move(prevNodePtr),
665 jittedActionOnHeap->SetAction(std::move(actionPtr));
666
667 doDeletes();
668}
669
670/// The contained `type` alias is `double` if `T == RInferredType`, `U` if `T == std::container<U>`, `T` otherwise.
671template <typename T, bool Container = IsDataContainer<T>::value && !std::is_same<T, std::string>::value>
672struct RMinReturnType {
673 using type = T;
674};
675
676template <>
678 using type = double;
679};
680
681template <typename T>
682struct RMinReturnType<T, true> {
683 using type = TTraits::TakeFirstParameter_t<T>;
684};
685
686// return wrapper around f that prepends an `unsigned int slot` parameter
687template <typename R, typename F, typename... Args>
688std::function<R(unsigned int, Args...)> AddSlotParameter(F &f, TypeList<Args...>)
689{
690 return [f](unsigned int, Args... a) mutable -> R { return f(a...); };
691}
692
693template <typename ColType, typename... Rest>
694struct RNeedJittingHelper {
695 static constexpr bool value = RNeedJittingHelper<Rest...>::value;
696};
697
698template <typename... Rest>
700 static constexpr bool value = true;
701};
702
703template <typename T>
704struct RNeedJittingHelper<T> {
705 static constexpr bool value = false;
706};
707
708template <>
710 static constexpr bool value = true;
711};
712
713template <typename ...ColTypes>
714struct RNeedJitting {
715 static constexpr bool value = RNeedJittingHelper<ColTypes...>::value;
716};
717
718template <>
719struct RNeedJitting<> {
720 static constexpr bool value = false;
721};
722
723///////////////////////////////////////////////////////////////////////////////
724/// Check preconditions for RInterface::Aggregate:
725/// - the aggregator callable must have signature `U(U,T)` or `void(U&,T)`.
726/// - the merge callable must have signature `U(U,U)` or `void(std::vector<U>&)`
727template <typename R, typename Merge, typename U, typename T, typename decayedU = std::decay_t<U>,
728 typename mergeArgsNoDecay_t = typename CallableTraits<Merge>::arg_types_nodecay,
729 typename mergeArgs_t = typename CallableTraits<Merge>::arg_types,
730 typename mergeRet_t = typename CallableTraits<Merge>::ret_type>
732{
733 constexpr bool isAggregatorOk =
734 (std::is_same<R, decayedU>::value) || (std::is_same<R, void>::value && std::is_lvalue_reference<U>::value);
735 static_assert(isAggregatorOk, "aggregator function must have signature `U(U,T)` or `void(U&,T)`");
736 constexpr bool isMergeOk =
737 (std::is_same<TypeList<decayedU, decayedU>, mergeArgs_t>::value && std::is_same<decayedU, mergeRet_t>::value) ||
738 (std::is_same<TypeList<std::vector<decayedU> &>, mergeArgsNoDecay_t>::value &&
739 std::is_same<void, mergeRet_t>::value);
740 static_assert(isMergeOk, "merge function must have signature `U(U,U)` or `void(std::vector<U>&)`");
741}
742
743///////////////////////////////////////////////////////////////////////////////
744/// This overload of CheckAggregate is called when the aggregator takes more than two arguments
745template <typename R, typename T>
746void CheckAggregate(T)
747{
748 static_assert(sizeof(T) == 0, "aggregator function must take exactly two arguments");
749}
750
751///////////////////////////////////////////////////////////////////////////////
752/// Check as many template parameters were passed as the number of column names, throw if this is not the case.
753void CheckTypesAndPars(unsigned int nTemplateParams, unsigned int nColumnNames);
754
755/// Return local BranchNames or default BranchNames according to which one should be used
756const ColumnNames_t SelectColumns(unsigned int nArgs, const ColumnNames_t &bl, const ColumnNames_t &defBl);
757
758/// Check whether column names refer to a valid branch of a TTree or have been `Define`d. Return invalid column names.
759ColumnNames_t FindUnknownColumns(const ColumnNames_t &requiredCols, const RColumnRegister &definedCols,
760 const ColumnNames_t &dataSourceColumns);
761
762/// Returns the list of Filters defined in the whole graph
763std::vector<std::string> GetFilterNames(const std::shared_ptr<RLoopManager> &loopManager);
764
765/// Returns the list of Filters defined in the branch
766template <typename NodeType>
767std::vector<std::string> GetFilterNames(const std::shared_ptr<NodeType> &node)
768{
769 std::vector<std::string> filterNames;
770 node->AddFilterName(filterNames);
771 return filterNames;
772}
773
774struct ParsedTreePath {
775 std::string fTreeName;
776 std::string fDirName;
777};
778
780
781// Check if a condition is true for all types
782template <bool...>
783struct TBoolPack;
784
785template <bool... bs>
786using IsTrueForAllImpl_t = typename std::is_same<TBoolPack<bs..., true>, TBoolPack<true, bs...>>;
787
788template <bool... Conditions>
789struct TEvalAnd {
790 static constexpr bool value = IsTrueForAllImpl_t<Conditions...>::value;
791};
792
793// Check if a class is a specialisation of stl containers templates
794// clang-format off
795
796template <typename>
797struct IsList_t : std::false_type {};
798
799template <typename T>
800struct IsList_t<std::list<T>> : std::true_type {};
801
802template <typename>
803struct IsDeque_t : std::false_type {};
804
805template <typename T>
806struct IsDeque_t<std::deque<T>> : std::true_type {};
807// clang-format on
808
809void CheckForDuplicateSnapshotColumns(const ColumnNames_t &cols);
810
811template <typename T>
812struct InnerValueType {
813 using type = T; // fallback for when T is not a nested RVec
814};
815
816template <typename Elem>
817struct InnerValueType<ROOT::VecOps::RVec<ROOT::VecOps::RVec<Elem>>> {
818 using type = Elem;
819};
820
821template <typename T>
823
824std::pair<std::vector<std::string>, std::vector<std::string>>
826 std::vector<std::string> &&colsWithAliases);
827
828void RemoveDuplicates(ColumnNames_t &columnNames);
829void RemoveRNTupleSubFields(ColumnNames_t &columnNames);
830
831} // namespace RDF
832} // namespace Internal
833
834namespace Detail {
835namespace RDF {
836
837/// The aliased type is `double` if `T == RInferredType`, `U` if `T == container<U>`, `T` otherwise.
838template <typename T>
839using MinReturnType_t = typename RDFInternal::RMinReturnType<T>::type;
840
841template <typename T>
843
844template <typename T>
846
847} // namespace RDF
848} // namespace Detail
849} // namespace ROOT
850
851/// \endcond
852
853#endif
#define f(i)
Definition RSha256.hxx:104
#define g(i)
Definition RSha256.hxx:105
#define a(i)
Definition RSha256.hxx:99
#define h(i)
Definition RSha256.hxx:106
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
Int_t gErrorIgnoreLevel
errors with level below this value will be ignored. Default is kUnset.
Definition TError.cxx:33
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char filename
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void value
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t Atom_t Atom_t Time_t type
char name[80]
Definition TGX11.cxx:110
The head node of a RDF computation graph.
A binder for user-defined columns, variations and aliases.
RDataSource defines an API that RDataFrame can use to read arbitrary data formats.
The public interface to the RDataFrame federation of classes.
const_iterator end() const
A "std::vector"-like collection of values implementing handy operation to analyse them.
Definition RVec.hxx:1525
@ kAllAxes
Definition TH1.h:126
A TTree represents a columnar dataset.
Definition TTree.h:89
#define F(x, y, z)
const ColumnNames_t SelectColumns(unsigned int nRequiredNames, const ColumnNames_t &names, const ColumnNames_t &defaultNames)
Choose between local column names or default column names, throw in case of errors.
void CheckForNoVariations(const std::string &where, std::string_view definedColView, const RColumnRegister &colRegister)
Throw if the column has systematic variations attached.
ParsedTreePath ParseTreePath(std::string_view fullTreeName)
std::shared_ptr< RJittedDefine > BookDefineJit(std::string_view name, std::string_view expression, RLoopManager &lm, RDataSource *ds, const RColumnRegister &colRegister, std::shared_ptr< RNodeBase > *upcastNodeOnHeap)
Book the jitting of a Define call.
void CheckValidCppVarName(std::string_view var, const std::string &where)
void RemoveDuplicates(ColumnNames_t &columnNames)
ColumnNames_t GetValidatedColumnNames(RLoopManager &lm, const unsigned int nColumns, const ColumnNames_t &columns, const RColumnRegister &colRegister, RDataSource *ds)
Given the desired number of columns and the user-provided list of columns:
std::shared_ptr< RNodeBase > UpcastNode(std::shared_ptr< RNodeBase > ptr)
std::shared_ptr< RDFDetail::RJittedFilter > BookFilterJit(std::shared_ptr< RDFDetail::RNodeBase > *prevNodeOnHeap, std::string_view name, std::string_view expression, const RColumnRegister &colRegister, TTree *tree, RDataSource *ds)
Book the jitting of a Filter call.
void CheckForDefinition(const std::string &where, std::string_view definedColView, const RColumnRegister &colRegister, const ColumnNames_t &dataSourceColumns)
Throw if column definedColView is not already there.
std::vector< std::string > GetFilterNames(const std::shared_ptr< RLoopManager > &loopManager)
std::string PrettyPrintAddr(const void *const addr)
void CheckTypesAndPars(unsigned int nTemplateParams, unsigned int nColumnNames)
std::string DemangleTypeIdName(const std::type_info &typeInfo)
bool AtLeastOneEmptyString(const std::vector< std::string_view > strings)
std::unique_ptr< ROOT::Detail::RDF::RColumnReaderBase > CreateColumnReader(ROOT::RDF::RDataSource &ds, unsigned int slot, std::string_view col, const std::type_info &tid, TTreeReader *treeReader)
Definition RDFUtils.cxx:671
std::pair< std::vector< std::string >, std::vector< std::string > > AddSizeBranches(ROOT::RDF::RDataSource *ds, std::vector< std::string > &&colsWithoutAliases, std::vector< std::string > &&colsWithAliases)
Return copies of colsWithoutAliases and colsWithAliases with size branches for variable-sized array b...
void RemoveRNTupleSubFields(ColumnNames_t &columnNames)
ColumnNames_t FilterArraySizeColNames(const ColumnNames_t &columnNames, const std::string &action)
Take a list of column names, return that list with entries starting by '#' filtered out.
std::vector< std::string > GetValidatedArgTypes(const ColumnNames_t &colNames, const RColumnRegister &colRegister, TTree *tree, RDataSource *ds, const std::string &context, bool vector2RVec)
std::shared_ptr< RJittedVariation > BookVariationJit(const std::vector< std::string > &colNames, std::string_view variationName, const std::vector< std::string > &variationTags, std::string_view expression, RLoopManager &lm, RDataSource *ds, const RColumnRegister &colRegister, std::shared_ptr< RNodeBase > *upcastNodeOnHeap, bool isSingleColumn)
Book the jitting of a Vary call.
void CheckForDuplicateSnapshotColumns(const ColumnNames_t &cols)
ColumnNames_t ConvertRegexToColumns(const ColumnNames_t &colNames, std::string_view columnNameRegexp, std::string_view callerName)
ColumnNames_t FindUnknownColumns(const ColumnNames_t &requiredCols, const RColumnRegister &definedCols, const ColumnNames_t &dataSourceColumns)
std::vector< bool > FindUndefinedDSColumns(const ColumnNames_t &requestedCols, const ColumnNames_t &definedCols)
Return a bitset each element of which indicates whether the corresponding element in selectedColumns ...
unsigned int & NThreadPerTH3()
Obtain or set the number of threads that will share a clone of a thread-safe 3D histogram.
Definition RDFUtils.cxx:63
std::shared_ptr< RJittedDefine > BookDefinePerSampleJit(std::string_view name, std::string_view expression, RLoopManager &lm, const RColumnRegister &colRegister, std::shared_ptr< RNodeBase > *upcastNodeOnHeap)
Book the jitting of a DefinePerSample call.
void CheckForRedefinition(const std::string &where, std::string_view definedColView, const RColumnRegister &colRegister, const ColumnNames_t &dataSourceColumns)
Throw if column definedColView is already there.
std::string JitBuildAction(const ColumnNames_t &cols, std::shared_ptr< RDFDetail::RNodeBase > *prevNode, const std::type_info &helperArgType, const std::type_info &at, void *helperArgOnHeap, TTree *tree, const unsigned int nSlots, const RColumnRegister &colRegister, RDataSource *ds, std::weak_ptr< RJittedAction > *jittedActionOnHeap, const bool vector2RVec)
ROOT type_traits extensions.
Namespace for new ROOT classes and functions.
Bool_t IsImplicitMTEnabled()
Returns true if the implicit multi-threading in ROOT is enabled.
Definition TROOT.cxx:600
A collection of options to steer the creation of the dataset on file.
Lightweight storage for a collection of types.