Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
TTreeProcessorMT.cxx
Go to the documentation of this file.
1// @(#)root/thread:$Id$
2// Authors: Enric Tejedor, Enrico Guiraud CERN 05/06/2018
3
4/*************************************************************************
5 * Copyright (C) 1995-2020, Rene Brun and Fons Rademakers. *
6 * All rights reserved. *
7 * *
8 * For the licensing terms see $ROOTSYS/LICENSE. *
9 * For the list of contributors see $ROOTSYS/README/CREDITS. *
10 *************************************************************************/
11
12/** \class ROOT::TTreeProcessorMT
13 \ingroup Parallelism
14 \brief A class to process the entries of a TTree in parallel.
15
16By means of its Process method, ROOT::TTreeProcessorMT provides a way to process the
17entries of a TTree in parallel. When invoking TTreeProcessor::Process, the user
18passes a function whose only parameter is a TTreeReader. The function iterates
19on a subrange of entries by using that TTreeReader.
20
21The implementation of ROOT::TTreeProcessorMT parallelizes the processing of the subranges,
22each corresponding to a cluster in the TTree. This is possible thanks to the use
23of a ROOT::TThreadedObject, so that each thread works with its own TFile and TTree
24objects.
25*/
26
27#include <cmath>
28#include <memory>
29
30#include "TROOT.h"
32
33using namespace ROOT;
34
35namespace {
36
37using EntryRange = std::pair<Long64_t, Long64_t>;
38
39// note that this routine assumes global entry numbers
40bool ClustersAreSortedAndContiguous(const std::vector<std::vector<EntryRange>> &cls)
41{
42 Long64_t last_end = 0ll;
43 for (const auto &fcl : cls) {
44 for (const auto &c : fcl) {
45 if (last_end != c.first)
46 return false;
47 last_end = c.second;
48 }
49 }
50 return true;
51}
52
53/// Take a vector of vectors of EntryRanges (a vector per file), filter the entries according to entryList, and
54/// and return a new vector of vectors of EntryRanges where cluster start/end entry numbers have been converted to
55/// TEntryList-local entry numbers.
56///
57/// This routine assumes that entry numbers in the TEntryList (and, if present, in the sub-entrylists) are in
58/// ascending order, i.e., for n > m:
59/// elist.GetEntry(n) + tree_offset_for_entry_from_elist(n) > elist.GetEntry(m) + tree_offset_for_entry_from_elist(m)
60std::vector<std::vector<EntryRange>>
61ConvertToElistClusters(std::vector<std::vector<EntryRange>> &&clusters, TEntryList &entryList,
62 const std::vector<std::string> &treeNames, const std::vector<std::string> &fileNames,
63 const std::vector<Long64_t> &entriesPerFile)
64{
65 R__ASSERT(entryList.GetN() > 0); // wasteful to call this function if it has nothing to do
67
68 const bool listHasGlobalEntryNumbers = entryList.GetLists() == nullptr;
69 const auto nFiles = clusters.size();
70
71 std::unique_ptr<TChain> chain;
72 using NextFn_t = Long64_t (*)(Long64_t &, TEntryList &, TChain *);
73 // A function that advances TEntryList and returns global entry numbers or -1 if we reached the end
74 // (might or might not need a TChain depending on whether listHasGlobalEntryNumbers)
75 NextFn_t Next;
77 Next = [](Long64_t &elEntry, TEntryList &elist, TChain *) {
78 ++elEntry;
79 return elist.Next();
80 };
81 } else {
82 // we need `chain` to be able to convert local entry numbers to global entry numbers in `Next`
84 for (auto i = 0u; i < nFiles; ++i)
85 chain->Add((fileNames[i] + "?#" + treeNames[i]).c_str(), entriesPerFile[i]);
86 Next = [](Long64_t &elEntry, TEntryList &elist, TChain *ch) {
87 ++elEntry;
88 int treenum = -1;
89 Long64_t localEntry = elist.GetEntryAndTree(elEntry, treenum);
90 if (localEntry == -1ll)
91 return localEntry;
92 return localEntry + ch->GetTreeOffset()[treenum];
93 };
94 }
95
96 // the call to GetEntry also serves the purpose to reset TEntryList::fLastIndexQueried,
97 // so we can be sure TEntryList::Next will return the correct thing
98 Long64_t elistEntry = 0ll;
100
101 std::vector<std::vector<EntryRange>> elistClusters;
102
103 for (auto fileN = 0u; fileN < nFiles; ++fileN) {
104 std::vector<EntryRange> elistClustersForFile;
105 for (const auto &c : clusters[fileN]) {
106 if (entry >= c.second || entry == -1ll) // no entrylist entries in this cluster
107 continue;
108 R__ASSERT(entry >= c.first); // current entry should never come before the cluster we are looking at
110 // advance entry list until the entrylist entry goes beyond the end of the cluster
111 while (entry < c.second && entry != -1ll)
112 entry = Next(elistEntry, entryList, chain.get());
113 elistClustersForFile.emplace_back(EntryRange{elistRangeStart, elistEntry});
114 }
115 elistClusters.emplace_back(std::move(elistClustersForFile));
116 }
117
118 R__ASSERT(elistClusters.size() == clusters.size()); // same number of files
120
121 entryList.GetEntry(0ll); // reset TEntryList internal state, lest we incur in ROOT-10807
122 return elistClusters;
123}
124
125// EntryRanges and number of entries per file
126using ClustersAndEntries = std::pair<std::vector<std::vector<EntryRange>>, std::vector<Long64_t>>;
127
128////////////////////////////////////////////////////////////////////////
129/// Return a vector of cluster boundaries for the given tree and files.
130ClustersAndEntries MakeClusters(const std::vector<std::string> &treeNames,
131 const std::vector<std::string> &fileNames, const unsigned int maxTasksPerFile,
132 const EntryRange &range = {0, std::numeric_limits<Long64_t>::max()})
133{
134 // Note that as a side-effect of opening all files that are going to be used in the
135 // analysis once, all necessary streamers will be loaded into memory.
137 const auto nFileNames = fileNames.size();
138 std::vector<std::vector<EntryRange>> clustersPerFile;
139 std::vector<Long64_t> entriesPerFile;
140 entriesPerFile.reserve(nFileNames);
141 Long64_t offset = 0ll;
142 bool rangeEndReached = false; // flag to break the outer loop
143 for (auto i = 0u; i < nFileNames && !rangeEndReached; ++i) {
144 const auto &fileName = fileNames[i];
145 const auto &treeName = treeNames[i];
146
147 std::unique_ptr<TFile> f(TFile::Open(
148 fileName.c_str(), "READ_WITHOUT_GLOBALREGISTRATION")); // need TFile::Open to load plugins if need be
149 if (!f || f->IsZombie()) {
150 const auto msg = "TTreeProcessorMT::Process: an error occurred while opening file \"" + fileName + "\"";
151 throw std::runtime_error(msg);
152 }
153 auto *t = f->Get<TTree>(treeName.c_str()); // t will be deleted by f
154
155 if (!t) {
156 const auto msg = "TTreeProcessorMT::Process: an error occurred while getting tree \"" + treeName +
157 "\" from file \"" + fileName + "\"";
158 throw std::runtime_error(msg);
159 }
160
161 // Avoid calling TROOT::RecursiveRemove for this tree, it takes the read lock and we don't need it.
162 t->ResetBit(kMustCleanup);
164 auto clusterIter = t->GetClusterIterator(0);
165 Long64_t clusterStart = 0ll, clusterEnd = 0ll;
166 const Long64_t entries = t->GetEntries();
167 // Iterate over the clusters in the current file
168 std::vector<EntryRange> entryRanges;
169 while ((clusterStart = clusterIter()) < entries && !rangeEndReached) {
170 clusterEnd = clusterIter.GetNextEntry();
171 // Currently, if a user specified a range, the clusters will be only globally obtained
172 // Assume that there are 3 files with entries: [0, 100], [0, 150], [0, 200] (in this order)
173 // Since the cluster boundaries are obtained sequentially, applying the offsets, the boundaries
174 // would be: 0, 100, 250, 450. Now assume that the user provided the range (150, 300)
175 // Then, in the first iteration, nothing is going to be added to entryRanges since:
176 // std::max(0, 150) < std::min(100, max). Then, by the same logic only a subset of the second
177 // tree is added, i.e.: currentStart is now 200 and currentEnd is 250 (locally from 100 to 150).
178 // Lastly, the last tree would take entries from 250 to 300 (or from 0 to 50 locally).
179 // The current file's offset to start and end is added to make them (chain) global
180 const auto currentStart = std::max(clusterStart + offset, range.first);
181 const auto currentEnd = std::min(clusterEnd + offset, range.second);
182 // This is not satified if the desired start is larger than the last entry of some cluster
183 // In this case, this cluster is not going to be processes further
185 entryRanges.emplace_back(EntryRange{currentStart, currentEnd});
186 if (currentEnd == range.second) // if the desired end is reached, stop reading further
187 rangeEndReached = true;
188 }
189 offset += entries; // consistently keep track of the total number of entries
190 clustersPerFile.emplace_back(std::move(entryRanges));
191 // Keep track of the entries, even if their corresponding tree is out of the range, e.g. entryRanges is empty
192 entriesPerFile.emplace_back(entries);
193 }
194 if (range.first >= offset && offset > 0) // do not error out on an empty tree
195 throw std::logic_error(std::string("A range of entries was passed in the creation of the TTreeProcessorMT, ") +
196 "but the starting entry (" + range.first + ") is larger than the total number of " +
197 "entries (" + offset + ") in the dataset.");
198
199 // Here we "fuse" clusters together if the number of clusters is too big with respect to
200 // the number of slots, otherwise we can incur in an overhead which is big enough
201 // to make parallelisation detrimental to performance.
202 // For example, this is the case when, following a merging of many small files, a file
203 // contains a tree with many entries and with clusters of just a few entries each.
204 // Another problematic case is a high number of slots (e.g. 256) coupled with a high number
205 // of files (e.g. 1000 files): the large amount of files might result in a large amount
206 // of tasks, but the elevated concurrency level makes the little synchronization required by
207 // task initialization very expensive. In this case it's better to simply process fewer, larger tasks.
208 // Cluster-merging can help reduce the number of tasks down to a minumum of one task per file.
209 //
210 // The criterion according to which we fuse clusters together is to have around
211 // TTreeProcessorMT::GetTasksPerWorkerHint() clusters per slot.
212 // Concretely, for each file we will cap the number of tasks to ceil(GetTasksPerWorkerHint() * nWorkers / nFiles).
213
214 std::vector<std::vector<EntryRange>> eventRangesPerFile(clustersPerFile.size());
218 const auto clustersInThisFileSize = clustersPerFileIt->size();
220 // If the number of clusters is less than maxTasksPerFile
221 // we take the clusters as they are
222 if (nFolds == 0) {
224 continue;
225 }
226 // Otherwise, we have to merge clusters, distributing the reminder evenly
227 // onto the first clusters
230 for (auto i = 0ULL; i < clustersInThisFileSize; ++i) {
231 const auto start = clustersInThisFile[i].first;
232 // We lump together at least nFolds clusters, therefore
233 // we need to jump ahead of nFolds-1.
234 i += (nFolds - 1);
235 // We now add a cluster if we have some reminder left
236 if (nReminderClusters > 0) {
237 i += 1U;
239 }
240 const auto end = clustersInThisFile[i].second;
241 eventRangesPerFileIt->emplace_back(EntryRange({start, end}));
242 }
243 }
244
245 return std::make_pair(std::move(eventRangesPerFile), std::move(entriesPerFile));
246}
247
248} // anonymous namespace
249
250namespace ROOT {
251
253
254namespace Internal {
255
256////////////////////////////////////////////////////////////////////////////////
257/// Construct fChain, also adding friends if needed and injecting knowledge of offsets if available.
258/// \param[in] treeNames Name of the tree for each file in `fileNames`.
259/// \param[in] fileNames Files to be opened.
260/// \param[in] friendInfo Information about TTree friends, if any.
261/// \param[in] nEntries Number of entries to be processed.
262/// \param[in] friendEntries Number of entries in each friend. Expected to have same ordering as friendInfo.
263void TTreeView::MakeChain(const std::vector<std::string> &treeNames, const std::vector<std::string> &fileNames,
264 const ROOT::TreeUtils::RFriendInfo &friendInfo, const std::vector<Long64_t> &nEntries)
265{
267 // Because of the range, we might have stopped reading entries earlier,
268 // hence the size of nEntries can be smaller than the number of all files
269 // TODO: pass "firstFileToProcess" index in case of a range,
270 // and do not add files to the chain, which are before the desired start entry of the range
271 const auto nFilesToProcess = nEntries.size();
272 for (auto i = 0u; i < nFilesToProcess; ++i) {
273 fChain->Add((fileNames[i] + "?#" + treeNames[i]).c_str(), nEntries[i]);
274 }
276
278 const auto nFriends = friendInfo.fFriendNames.size();
279 R__ASSERT(nFriends == fFriends.size() && "Created the wrong number of friends from the available information.");
280 for (std::size_t i = 0ul; i < nFriends; i++) {
281 const auto &thisFriendAlias = friendInfo.fFriendNames[i].second;
282 fChain->AddFriend(fFriends[i].get(), thisFriendAlias.c_str());
283 }
284}
285
286//////////////////////////////////////////////////////////////////////////
287/// Get a TTreeReader for the current tree of this view.
288std::unique_ptr<TTreeReader>
289TTreeView::GetTreeReader(Long64_t start, Long64_t end, const std::vector<std::string> &treeNames,
290 const std::vector<std::string> &fileNames, const ROOT::TreeUtils::RFriendInfo &friendInfo,
291 const TEntryList &entryList, const std::vector<Long64_t> &nEntries,
292 const std::set<std::string> &suppressErrorsForMissingBranches)
293{
294 const bool hasEntryList = entryList.GetN() > 0;
295 const bool usingLocalEntries = friendInfo.fFriendNames.empty() && !hasEntryList;
296 const bool needNewChain =
297 fChain == nullptr || (usingLocalEntries && (fileNames[0] != fChain->GetListOfFiles()->At(0)->GetTitle() ||
298 treeNames[0] != fChain->GetListOfFiles()->At(0)->GetName()));
299 if (needNewChain) {
301 if (hasEntryList) {
302 fEntryList = std::make_unique<TEntryList>(entryList);
303 if (fEntryList->GetLists() != nullptr) {
304 // need to associate the TEntryList to the TChain for the latter to set entry the fTreeNumbers of the
305 // sub-lists of the former...
306 fChain->SetEntryList(fEntryList.get());
307 fEntryList->ResetBit(TObject::kCanDelete); // ...but we want to retain ownership
308 }
309 }
310 }
311 auto reader = std::make_unique<TTreeReader>(fChain.get(), fEntryList.get(), /*warnAboutLongerFriends*/ false,
313 reader->SetEntriesRange(start, end);
314 return reader;
315}
316
317////////////////////////////////////////////////////////////////////////
318/// Clear the resources
320{
321 fChain.reset();
322 fEntryList.reset();
323 fFriends.clear();
324}
325
326} // namespace Internal
327} // namespace ROOT
328
329/////////////////////////////////////////////////////////////////////////////////////////////////
330/// Retrieve the names of the TTrees in each of the input files, throw if a TTree cannot be found.
331std::vector<std::string> TTreeProcessorMT::FindTreeNames()
332{
333 std::vector<std::string> treeNames;
334
335 if (fFileNames.empty()) // This can never happen
336 throw std::runtime_error("Empty list of files and no tree name provided");
337
339 for (const auto &fname : fFileNames) {
340 std::string treeName;
341 std::unique_ptr<TFile> f(TFile::Open(fname.c_str()));
342 TIter next(f->GetListOfKeys());
343 while (auto *key = static_cast<TKey *>(next())) {
344 const char *className = key->GetClassName();
345 if (strcmp(className, "TTree") == 0) {
346 treeName = key->GetName();
347 break;
348 }
349 }
350 if (treeName.empty())
351 throw std::runtime_error("Cannot find any tree in file " + fname);
352 treeNames.emplace_back(std::move(treeName));
353 }
354
355 return treeNames;
356}
357
358////////////////////////////////////////////////////////////////////////
359/// Constructor based on a file name.
360/// \param[in] filename Name of the file containing the tree to process.
361/// \param[in] treename Name of the tree to process. If not provided, the implementation will search
362/// for a TTree key in the file and will use the first one it finds.
363/// \param[in] nThreads Number of threads to create in the underlying thread-pool. The semantics of this argument are
364/// the same as for TThreadExecutor.
365/// \param[in] /// \param[in] globalRange Global entry range to process, {begin (inclusive), end (exclusive)}.
366TTreeProcessorMT::TTreeProcessorMT(std::string_view filename, std::string_view treename, UInt_t nThreads,
367 const EntryRange &globalRange)
368 : fFileNames({std::string(filename)}),
369 fTreeNames(treename.empty() ? FindTreeNames() : std::vector<std::string>{std::string(treename)}), fFriendInfo(),
370 fPool(nThreads), fGlobalRange(globalRange)
371{
373}
374
375std::vector<std::string> CheckAndConvert(const std::vector<std::string_view> &views)
376{
377 if (views.empty())
378 throw std::runtime_error("The provided list of file names is empty");
379
380 std::vector<std::string> strings;
381 strings.reserve(views.size());
382 for (const auto &v : views)
383 strings.emplace_back(v);
384 return strings;
385}
386
387////////////////////////////////////////////////////////////////////////
388/// Constructor based on a collection of file names.
389/// \param[in] filenames Collection of the names of the files containing the tree to process.
390/// \param[in] treename Name of the tree to process. If not provided, the implementation will
391/// search filenames for a TTree key and will use the first one it finds in each file.
392/// \param[in] nThreads Number of threads to create in the underlying thread-pool. The semantics of this argument are
393/// the same as for TThreadExecutor.
394/// \param[in] globalRange Global entry range to process, {begin (inclusive), end (exclusive)}.
395///
396/// If different files contain TTrees with different names and automatic TTree name detection is not an option
397/// (for example, because some of the files contain multiple TTrees) please manually create a TChain and pass
398/// it to the appropriate TTreeProcessorMT constructor.
399TTreeProcessorMT::TTreeProcessorMT(const std::vector<std::string_view> &filenames, std::string_view treename,
400 UInt_t nThreads, const EntryRange &globalRange)
401 : fFileNames(CheckAndConvert(filenames)),
402 fTreeNames(treename.empty() ? FindTreeNames()
403 : std::vector<std::string>(fFileNames.size(), std::string(treename))),
404 fFriendInfo(), fPool(nThreads), fGlobalRange(globalRange)
405{
407}
408
409////////////////////////////////////////////////////////////////////////
410/// Constructor based on a TTree and a TEntryList.
411/// \param[in] tree Tree or chain of files containing the tree to process.
412/// \param[in] entries List of entry numbers to process.
413/// \param[in] nThreads Number of threads to create in the underlying thread-pool. The semantics of this argument are
414/// the same as for TThreadExecutor.
416 const std::set<std::string> &suppressErrorsForMissingBranches)
417 : fFileNames(Internal::TreeUtils::GetFileNamesFromTree(tree)),
418 fTreeNames(Internal::TreeUtils::GetTreeFullPaths(tree)),
419 fEntryList(entries),
420 fFriendInfo(Internal::TreeUtils::GetFriendInfo(tree, /*retrieveEntries*/ true)),
421 fPool(nThreads),
422 fSuppressErrorsForMissingBranches(suppressErrorsForMissingBranches)
423{
425}
426
427////////////////////////////////////////////////////////////////////////
428/// Constructor based on a TTree.
429/// \param[in] tree Tree or chain of files containing the tree to process.
430/// \param[in] nThreads Number of threads to create in the underlying thread-pool. The semantics of this argument are
431/// the same as for TThreadExecutor.
432/// \param[in] globalRange Global entry range to process, {begin (inclusive), end (exclusive)}.
434 const std::set<std::string> &suppressErrorsForMissingBranches)
435 : fFileNames(Internal::TreeUtils::GetFileNamesFromTree(tree)),
436 fTreeNames(Internal::TreeUtils::GetTreeFullPaths(tree)),
437 fFriendInfo(Internal::TreeUtils::GetFriendInfo(tree, /*retrieveEntries*/ true)),
438 fPool(nThreads),
439 fGlobalRange(globalRange),
440 fSuppressErrorsForMissingBranches(suppressErrorsForMissingBranches)
441{
442}
443
444//////////////////////////////////////////////////////////////////////////////
445/// Process the entries of a TTree in parallel. The user-provided function
446/// receives a TTreeReader which can be used to iterate on a subrange of
447/// entries
448/// ~~~{.cpp}
449/// TTreeProcessorMT::Process([](TTreeReader& readerSubRange) {
450/// // Select branches to read
451/// while (readerSubRange.Next()) {
452/// // Use content of current entry
453/// }
454/// });
455/// ~~~
456/// The user needs to be aware that each of the subranges can potentially
457/// be processed in parallel. This means that the code of the user function
458/// should be thread safe.
459///
460/// \param[in] func User-defined function that processes a subrange of entries
461void TTreeProcessorMT::Process(std::function<void(TTreeReader &)> func)
462{
463 // compute number of tasks per file
464 const unsigned int maxTasksPerFile =
465 std::ceil(float(GetTasksPerWorkerHint() * fPool.GetPoolSize()) / float(fFileNames.size()));
466
467 // If an entry list or friend trees are present, we need to generate clusters with global entry numbers,
468 // so we do it here for all files.
469 // Otherwise we can do it later, concurrently for each file, and clusters will contain local entry numbers.
470 // TODO: in practice we could also find clusters per-file in the case of no friends and a TEntryList with
471 // sub-entrylists.
472 const bool hasFriends = !fFriendInfo.fFriendNames.empty();
473 const bool hasEntryList = fEntryList.GetN() > 0;
474 const bool shouldRetrieveAllClusters = hasFriends || hasEntryList || fGlobalRange.first > 0 ||
475 fGlobalRange.second != std::numeric_limits<Long64_t>::max();
477 auto &allClusters = allClusterAndEntries.first;
478 const auto &allEntries = allClusterAndEntries.second;
481 if (hasEntryList)
483 }
484
485 // Per-file processing in case we retrieved all cluster info upfront
486 auto processFileUsingGlobalClusters = [&](std::size_t fileIdx) {
487 auto processCluster = [&](const EntryRange &c) {
490 func(*r);
491 };
493 };
494
495 // Per-file processing that also retrieves cluster info for a file
496 auto processFileRetrievingClusters = [&](std::size_t fileIdx) {
497 // Evaluate clusters (with local entry numbers) and number of entries for this file
498 const auto &treeNames = std::vector<std::string>({fTreeNames[fileIdx]});
499 const auto &fileNames = std::vector<std::string>({fFileNames[fileIdx]});
501 const auto &clusters = clustersAndEntries.first[0];
502 const auto &entries = clustersAndEntries.second[0];
503 auto processCluster = [&](const EntryRange &c) {
504 auto r = fTreeView->GetTreeReader(c.first, c.second, treeNames, fileNames, fFriendInfo, fEntryList, {entries},
506 func(*r);
507 };
509 };
510
511 const auto firstNonEmpty =
512 fGlobalRange.first > 0u ? std::distance(allClusters.begin(), std::find_if(allClusters.begin(), allClusters.end(),
513 [](auto &c) { return !c.empty(); }))
514 : 0u;
515
516 std::vector<std::size_t> fileIdxs(allEntries.empty() ? fFileNames.size() : allEntries.size() - firstNonEmpty);
517 std::iota(fileIdxs.begin(), fileIdxs.end(), firstNonEmpty);
518
521 else
523
524 // make sure TChains and TFiles are cleaned up since they are not globally tracked
525 for (unsigned int islot = 0; islot < fTreeView.GetNSlots(); ++islot) {
526 ROOT::Internal::TTreeView *view = fTreeView.GetAtSlotRaw(islot);
527 if (view != nullptr) {
528 view->Reset();
529 }
530 }
531}
532
533////////////////////////////////////////////////////////////////////////
534/// \brief Retrieve the current value for the desired number of tasks per worker.
535/// \return The desired number of tasks to be created per worker. TTreeProcessorMT uses this value as an hint.
540
541////////////////////////////////////////////////////////////////////////
542/// \brief Set the hint for the desired number of tasks created per worker.
543/// \param[in] tasksPerWorkerHint Desired number of tasks per worker.
544///
545/// This allows to create a reasonable number of tasks even if any of the
546/// processed files features a bad clustering, for example with a lot of
547/// entries and just a few entries per cluster, or to limit the number of
548/// tasks spawned when a very large number of files and workers is used.
#define f(i)
Definition RSha256.hxx:104
#define c(i)
Definition RSha256.hxx:101
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
long long Long64_t
Portable signed long integer 8 bytes.
Definition RtypesCore.h:83
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
#define gDirectory
Definition TDirectory.h:385
#define R__ASSERT(e)
Checks condition e and reports a fatal error if it's false.
Definition TError.h:125
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 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 offset
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 r
@ kMustCleanup
Definition TObject.h:371
std::vector< std::string > CheckAndConvert(const std::vector< std::string_view > &views)
std::unique_ptr< TChain > fChain
Chain on which to operate.
std::vector< std::unique_ptr< TChain > > fFriends
Friends of the tree/chain, if present.
std::unique_ptr< TEntryList > fEntryList
TEntryList for fChain, if present.
void Reset()
Clear the resources.
std::unique_ptr< TTreeReader > GetTreeReader(Long64_t start, Long64_t end, const std::vector< std::string > &treeName, const std::vector< std::string > &fileNames, const ROOT::TreeUtils::RFriendInfo &friendInfo, const TEntryList &entryList, const std::vector< Long64_t > &nEntries, const std::set< std::string > &suppressErrorsForMissingBranches)
Get a TTreeReader for the current tree of this view.
void MakeChain(const std::vector< std::string > &treeName, const std::vector< std::string > &fileNames, const ROOT::TreeUtils::RFriendInfo &friendInfo, const std::vector< Long64_t > &nEntries)
Construct fChain, also adding friends if needed and injecting knowledge of offsets if available.
ROOT::Internal::TreeUtils::RNoCleanupNotifier fNoCleanupNotifier
const_iterator begin() const
const_iterator end() const
unsigned GetPoolSize() const
Returns the number of worker threads in the task arena.
void Foreach(F func, unsigned nTimes, unsigned nChunks=0)
Execute a function without arguments several times in parallel, dividing the execution in nChunks.
ROOT::TreeUtils::RFriendInfo fFriendInfo
const std::vector< std::string > fTreeNames
TTree names (always same size and ordering as fFileNames)
std::vector< std::string > FindTreeNames()
Retrieve the names of the TTrees in each of the input files, throw if a TTree cannot be found.
const std::vector< std::string > fFileNames
Names of the files.
static unsigned int fgTasksPerWorkerHint
ROOT::TThreadExecutor fPool
! Thread pool for processing.
TEntryList fEntryList
User-defined selection of entry numbers to be processed, empty if none was provided.
static void SetTasksPerWorkerHint(unsigned int m)
Set the hint for the desired number of tasks created per worker.
ROOT::TThreadedObject< ROOT::Internal::TTreeView > fTreeView
Thread-local TreeViews.
std::set< std::string > fSuppressErrorsForMissingBranches
void Process(std::function< void(TTreeReader &)> func)
Process the entries of a TTree in parallel.
TTreeProcessorMT(std::string_view filename, std::string_view treename="", UInt_t nThreads=0u, const std::pair< Long64_t, Long64_t > &globalRange={0, std::numeric_limits< Long64_t >::max()})
static unsigned int GetTasksPerWorkerHint()
Retrieve the current value for the desired number of tasks per worker.
std::pair< Long64_t, Long64_t > fGlobalRange
A chain is a collection of files containing TTree objects.
Definition TChain.h:33
TDirectory::TContext keeps track and restore the current directory.
Definition TDirectory.h:89
A List of entry numbers in a TTree or TChain.
Definition TEntryList.h:26
virtual Long64_t GetN() const
Definition TEntryList.h:78
static TFile * Open(const char *name, Option_t *option="", const char *ftitle="", Int_t compress=ROOT::RCompressionSetting::EDefaults::kUseCompiledDefault, Int_t netopt=0)
Create / open a file.
Definition TFile.cxx:3765
Book space in a file, create I/O buffers, to fill them, (un)compress them.
Definition TKey.h:28
@ kCanDelete
if object in a list can be deleted
Definition TObject.h:68
A simple, robust and fast interface to read values from ROOT columnar datasets such as TTree,...
Definition TTreeReader.h:46
A TTree represents a columnar dataset.
Definition TTree.h:89
Different standalone functions to work with trees and tuples, not reqiuired to be a member of any cla...
std::unique_ptr< TChain > MakeChainForMT(const std::string &name="", const std::string &title="")
Create a TChain object with options that avoid common causes of thread contention.
std::vector< std::unique_ptr< TChain > > MakeFriends(const ROOT::TreeUtils::RFriendInfo &finfo)
Create friends from the main TTree.
void ClearMustCleanupBits(TObjArray &arr)
Reset the kMustCleanup bit of a TObjArray of TBranch objects (e.g.
Namespace for new ROOT classes and functions.
void EnableThreadSafety()
Enable support for multi-threading within the ROOT code in particular, enables the global mutex to ma...
Definition TROOT.cxx:506
Information about friend trees of a certain TTree or TChain object.
std::vector< std::pair< std::string, std::string > > fFriendNames
Pairs of names and aliases of each friend tree/chain.