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