Logo ROOT  
Reference Guide
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-2016, 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 "TROOT.h"
30
31using namespace ROOT;
32
33namespace ROOT {
34
36
37namespace Internal {
38
39/// A cluster of entries
40struct EntryCluster {
41 Long64_t start;
42 Long64_t end;
43};
44
45////////////////////////////////////////////////////////////////////////////////
46/// Construct fChain, also adding friends if needed and injecting knowledge of offsets if available.
47void TTreeView::MakeChain(const std::vector<std::string> &treeNames, const std::vector<std::string> &fileNames,
48 const FriendInfo &friendInfo, const std::vector<Long64_t> &nEntries,
49 const std::vector<std::vector<Long64_t>> &friendEntries)
50{
51 const std::vector<NameAlias> &friendNames = friendInfo.fFriendNames;
52 const std::vector<std::vector<std::string>> &friendFileNames = friendInfo.fFriendFileNames;
53
54 fChain.reset(new TChain());
55 const auto nFiles = fileNames.size();
56 for (auto i = 0u; i < nFiles; ++i) {
57 fChain->Add((fileNames[i] + "/" + treeNames[i]).c_str(), nEntries[i]);
58 }
60
61 fFriends.clear();
62 const auto nFriends = friendNames.size();
63 for (auto i = 0u; i < nFriends; ++i) {
64 const auto &friendName = friendNames[i];
65 const auto &name = friendName.first;
66 const auto &alias = friendName.second;
67
68 // Build a friend chain
69 auto frChain = std::make_unique<TChain>(name.c_str());
70 const auto nFileNames = friendFileNames[i].size();
71 for (auto j = 0u; j < nFileNames; ++j)
72 frChain->Add(friendFileNames[i][j].c_str(), friendEntries[i][j]);
73
74 // Make it friends with the main chain
75 fChain->AddFriend(frChain.get(), alias.c_str());
76 fFriends.emplace_back(std::move(frChain));
77 }
78}
79
82{
83 // TEntryList and SetEntriesRange do not work together (the former has precedence).
84 // We need to construct a TEntryList that contains only those entry numbers in our desired range.
85
86 std::vector<TEntryList*> globalEntryLists;
87 auto innerLists = globalList.GetLists();
88 if (!innerLists) {
89 if (globalList.GetN()) {
90 globalEntryLists.emplace_back(&globalList);
91 }
92 } else {
93 for (auto lp : *innerLists) {
94 auto lpAsTEntryList = static_cast<TEntryList *>(lp);
95 if (lpAsTEntryList->GetN()) {
96 globalEntryLists.emplace_back(lpAsTEntryList);
97 }
98 }
99 }
100
101 auto localList = std::make_unique<TEntryList>();
102
103 for (auto gl : globalEntryLists) {
104 Long64_t entry = gl->GetEntry(0);
105
106 // this may be owned by the local list
107 auto tmp_list = new TEntryList(gl->GetName(), gl->GetTitle(), gl->GetFileName(), gl->GetTreeName());
108
109 do {
110 if (entry >= end) {
111 break;
112 } else if (entry >= start) {
113 tmp_list->Enter(entry);
114 }
115 } while ((entry = gl->Next()) >= 0);
116
117 if (tmp_list->GetN() > 0) {
118 localList->Add(tmp_list);
119 } else {
120 delete tmp_list;
121 }
122 }
123
124 auto reader = std::make_unique<TTreeReader>(fChain.get(), localList.get());
125 return std::make_pair(std::move(reader), std::move(localList));
126}
127
128std::unique_ptr<TTreeReader> TTreeView::MakeReader(Long64_t start, Long64_t end)
129{
130 auto reader = std::make_unique<TTreeReader>(fChain.get());
131 reader->SetEntriesRange(start, end);
132 return reader;
133}
134
135//////////////////////////////////////////////////////////////////////////
136/// Get a TTreeReader for the current tree of this view.
138TTreeView::GetTreeReader(Long64_t start, Long64_t end, const std::vector<std::string> &treeNames,
139 const std::vector<std::string> &fileNames, const FriendInfo &friendInfo, TEntryList entryList,
140 const std::vector<Long64_t> &nEntries, const std::vector<std::vector<Long64_t>> &friendEntries)
141{
142 const bool usingLocalEntries = friendInfo.fFriendNames.empty() && entryList.GetN() == 0;
143 if (fChain == nullptr || (usingLocalEntries && fileNames[0] != fChain->GetListOfFiles()->At(0)->GetTitle()))
144 MakeChain(treeNames, fileNames, friendInfo, nEntries, friendEntries);
145
146 std::unique_ptr<TTreeReader> reader;
147 std::unique_ptr<TEntryList> localList;
148 if (entryList.GetN() > 0) {
149 std::tie(reader, localList) = MakeReaderWithEntryList(entryList, start, end);
150 } else {
151 reader = MakeReader(start, end);
152 }
153
154 // we need to return the entry list too, as it needs to be in scope as long as the reader is
155 return std::make_pair(std::move(reader), std::move(localList));
156}
157
158////////////////////////////////////////////////////////////////////////
159/// Return a vector of cluster boundaries for the given tree and files.
160// EntryClusters and number of entries per file
161using ClustersAndEntries = std::pair<std::vector<std::vector<EntryCluster>>, std::vector<Long64_t>>;
163MakeClusters(const std::vector<std::string> &treeNames, const std::vector<std::string> &fileNames)
164{
165 // Note that as a side-effect of opening all files that are going to be used in the
166 // analysis once, all necessary streamers will be loaded into memory.
168 const auto nFileNames = fileNames.size();
169 std::vector<std::vector<EntryCluster>> clustersPerFile;
170 std::vector<Long64_t> entriesPerFile;
171 entriesPerFile.reserve(nFileNames);
172 Long64_t offset = 0ll;
173 for (auto i = 0u; i < nFileNames; ++i) {
174 const auto &fileName = fileNames[i];
175 const auto &treeName = treeNames[i];
176
177 std::unique_ptr<TFile> f(TFile::Open(fileName.c_str())); // need TFile::Open to load plugins if need be
178 if (!f || f->IsZombie()) {
179 Error("TTreeProcessorMT::Process", "An error occurred while opening file %s: skipping it.", fileName.c_str());
180 clustersPerFile.emplace_back(std::vector<EntryCluster>());
181 entriesPerFile.emplace_back(0ULL);
182 continue;
183 }
184 TTree *t = nullptr; // not a leak, t will be deleted by f
185 f->GetObject(treeName.c_str(), t);
186
187 if (!t) {
188 Error("TTreeProcessorMT::Process", "An error occurred while getting tree %s from file %s: skipping this file.",
189 treeName.c_str(), fileName.c_str());
190 clustersPerFile.emplace_back(std::vector<EntryCluster>());
191 entriesPerFile.emplace_back(0ULL);
192 continue;
193 }
194
195 auto clusterIter = t->GetClusterIterator(0);
196 Long64_t start = 0ll, end = 0ll;
197 const Long64_t entries = t->GetEntries();
198 // Iterate over the clusters in the current file
199 std::vector<EntryCluster> clusters;
200 while ((start = clusterIter()) < entries) {
201 end = clusterIter.GetNextEntry();
202 // Add the current file's offset to start and end to make them (chain) global
203 clusters.emplace_back(EntryCluster{start + offset, end + offset});
204 }
205 offset += entries;
206 clustersPerFile.emplace_back(std::move(clusters));
207 entriesPerFile.emplace_back(entries);
208 }
209
210 // Here we "fuse" together clusters if the number of clusters is to big with respect to
211 // the number of slots, otherwise we can incurr in an overhead which is so big to make
212 // the parallelisation detrimental for performance.
213 // For example, this is the case when following a merging of many small files a file
214 // contains a tree with many entries and with clusters of just a few entries.
215 // The criterion according to which we fuse clusters together is to have at most
216 // TTreeProcessorMT::GetMaxTasksPerFilePerWorker() clusters per file per slot.
217 // For example: given 2 files and 16 workers, at most
218 // 16 * 2 * TTreeProcessorMT::GetMaxTasksPerFilePerWorker() clusters will be created, at most
219 // 16 * TTreeProcessorMT::GetMaxTasksPerFilePerWorker() per file.
220
222 std::vector<std::vector<EntryCluster>> eventRangesPerFile(clustersPerFile.size());
223 auto clustersPerFileIt = clustersPerFile.begin();
224 auto eventRangesPerFileIt = eventRangesPerFile.begin();
225 for (; clustersPerFileIt != clustersPerFile.end(); clustersPerFileIt++, eventRangesPerFileIt++) {
226 const auto clustersInThisFileSize = clustersPerFileIt->size();
227 const auto nFolds = clustersInThisFileSize / maxTasksPerFile;
228 // If the number of clusters is less than maxTasksPerFile
229 // we take the clusters as they are
230 if (nFolds == 0) {
231 std::for_each(
232 clustersPerFileIt->begin(), clustersPerFileIt->end(),
233 [&eventRangesPerFileIt](const EntryCluster &clust) { eventRangesPerFileIt->emplace_back(clust); });
234 continue;
235 }
236 // Otherwise, we have to merge clusters, distributing the reminder evenly
237 // onto the first clusters
238 auto nReminderClusters = clustersInThisFileSize % maxTasksPerFile;
239 const auto clustersInThisFile = *clustersPerFileIt;
240 for (auto i = 0ULL; i < clustersInThisFileSize; ++i) {
241 const auto start = clustersInThisFile[i].start;
242 // We lump together at least nFolds clusters, therefore
243 // we need to jump ahead of nFolds-1.
244 i += (nFolds - 1);
245 // We now add a cluster if we have some reminder left
246 if (nReminderClusters > 0) {
247 i += 1U;
248 nReminderClusters--;
249 }
250 const auto end = clustersInThisFile[i].end;
251 eventRangesPerFileIt->emplace_back(EntryCluster({start, end}));
252 }
253 }
254
255 return std::make_pair(std::move(eventRangesPerFile), std::move(entriesPerFile));
256}
257
258////////////////////////////////////////////////////////////////////////
259/// Return a vector containing the number of entries of each file of each friend TChain
260static std::vector<std::vector<Long64_t>>
261GetFriendEntries(const std::vector<std::pair<std::string, std::string>> &friendNames,
262 const std::vector<std::vector<std::string>> &friendFileNames)
263{
264 std::vector<std::vector<Long64_t>> friendEntries;
265 const auto nFriends = friendNames.size();
266 for (auto i = 0u; i < nFriends; ++i) {
267 std::vector<Long64_t> nEntries;
268 const auto &thisFriendName = friendNames[i].first;
269 const auto &thisFriendFiles = friendFileNames[i];
270 for (const auto &fname : thisFriendFiles) {
271 std::unique_ptr<TFile> f(TFile::Open(fname.c_str()));
272 TTree *t = nullptr; // owned by TFile
273 f->GetObject(thisFriendName.c_str(), t);
274 nEntries.emplace_back(t->GetEntries());
275 }
276 friendEntries.emplace_back(std::move(nEntries));
277 }
278
279 return friendEntries;
280}
281
282////////////////////////////////////////////////////////////////////////
283/// Return the full path of the TTree or the trees in the TChain
284static std::vector<std::string> GetTreeFullPaths(const TTree &tree)
285{
286 // Case 1: this is a TChain. For each file it contains, GetName returns the name of the tree in that file
287 if (tree.IsA() == TChain::Class()) {
288 auto &chain = static_cast<const TChain &>(tree);
289 auto files = chain.GetListOfFiles();
290 if (!files || files->GetEntries() == 0) {
291 throw std::runtime_error("TTreeProcessorMT: input TChain does not contain any file");
292 }
293 std::vector<std::string> treeNames;
294 for (TObject *f : *files)
295 treeNames.emplace_back(f->GetName());
296
297 return treeNames;
298 }
299
300 // Case 2: this is a TTree: we get the full path of it
301 if (auto motherDir = tree.GetDirectory()) {
302 // We have 2 subcases (ROOT-9948):
303 // - 1. motherDir is a TFile
304 // - 2. motherDir is a directory
305 // If 1. we just return the name of the tree, if 2. we reconstruct the path
306 // to the file.
307 if (motherDir->InheritsFrom("TFile")) {
308 return {tree.GetName()};
309 }
310 std::string fullPath(motherDir->GetPath());
311 fullPath += "/";
312 fullPath += tree.GetName();
313 return {fullPath};
314 }
315
316 // We do our best and return the name of the tree
317 return {tree.GetName()};
318}
319
320} // namespace Internal
321} // namespace ROOT
322
323////////////////////////////////////////////////////////////////////////////////
324/// Get and store the names, aliases and file names of the friends of the tree.
325/// \param[in] tree The main tree whose friends to
326///
327/// Note that "friends of friends" and circular references in the lists of friends are not supported.
328Internal::FriendInfo TTreeProcessorMT::GetFriendInfo(TTree &tree)
329{
330 std::vector<Internal::NameAlias> friendNames;
331 std::vector<std::vector<std::string>> friendFileNames;
332
333 const auto friends = tree.GetListOfFriends();
334 if (!friends)
335 return Internal::FriendInfo();
336
337 for (auto fr : *friends) {
338 const auto frTree = static_cast<TFriendElement *>(fr)->GetTree();
339
340 // Check if friend tree has an alias
341 const auto realName = frTree->GetName();
342 const auto alias = tree.GetFriendAlias(frTree);
343 if (alias) {
344 friendNames.emplace_back(std::make_pair(realName, std::string(alias)));
345 } else {
346 friendNames.emplace_back(std::make_pair(realName, ""));
347 }
348
349 // Store the file names of the friend tree
350 friendFileNames.emplace_back();
351 auto &fileNames = friendFileNames.back();
352 const bool isChain = tree.IsA() == TChain::Class();
353 if (isChain) {
354 const auto frChain = static_cast<TChain *>(frTree);
355 for (auto f : *(frChain->GetListOfFiles())) {
356 fileNames.emplace_back(f->GetTitle());
357 }
358 } else {
359 const auto f = frTree->GetCurrentFile();
360 if (!f)
361 throw std::runtime_error("Friend trees with no associated file are not supported.");
362 fileNames.emplace_back(f->GetName());
363 }
364 }
365
366 return Internal::FriendInfo{std::move(friendNames), std::move(friendFileNames)};
367}
368
369/////////////////////////////////////////////////////////////////////////////////////////////////
370/// Retrieve the names of the TTrees in each of the input files, throw if a TTree cannot be found.
371std::vector<std::string> TTreeProcessorMT::FindTreeNames()
372{
373 std::vector<std::string> treeNames;
374
375 if (fFileNames.empty()) // This can never happen
376 throw std::runtime_error("Empty list of files and no tree name provided");
377
379 for (const auto &fname : fFileNames) {
380 std::string treeName;
381 std::unique_ptr<TFile> f(TFile::Open(fname.c_str()));
382 TIter next(f->GetListOfKeys());
383 while (auto *key = static_cast<TKey *>(next())) {
384 const char *className = key->GetClassName();
385 if (strcmp(className, "TTree") == 0) {
386 treeName = key->GetName();
387 break;
388 }
389 }
390 if (treeName.empty())
391 throw std::runtime_error("Cannot find any tree in file " + fname);
392 treeNames.emplace_back(std::move(treeName));
393 }
394
395 return treeNames;
396}
397
398////////////////////////////////////////////////////////////////////////
399/// Constructor based on a file name.
400/// \param[in] filename Name of the file containing the tree to process.
401/// \param[in] treename Name of the tree to process. If not provided, the implementation will search
402/// for a TTree key in the file and will use the first one it finds.
404 : fFileNames({std::string(filename)}),
405 fTreeNames(treename.empty() ? FindTreeNames() : std::vector<std::string>{std::string(treename)}), fFriendInfo()
406{
407}
408
409std::vector<std::string> CheckAndConvert(const std::vector<std::string_view> &views)
410{
411 if (views.empty())
412 throw std::runtime_error("The provided list of file names is empty");
413
414 std::vector<std::string> strings;
415 strings.reserve(views.size());
416 for (const auto &v : views)
417 strings.emplace_back(v);
418 return strings;
419}
420
421////////////////////////////////////////////////////////////////////////
422/// Constructor based on a collection of file names.
423/// \param[in] filenames Collection of the names of the files containing the tree to process.
424/// \param[in] treename Name of the tree to process. If not provided, the implementation will
425/// search filenames for a TTree key and will use the first one it finds in each file.
426///
427/// If different files contain TTrees with different names and automatic TTree name detection is not an option
428/// (for example, because some of the files contain multiple TTrees) please manually create a TChain and pass
429/// it to the appropriate TTreeProcessorMT constructor.
430TTreeProcessorMT::TTreeProcessorMT(const std::vector<std::string_view> &filenames, std::string_view treename)
431 : fFileNames(CheckAndConvert(filenames)),
432 fTreeNames(treename.empty() ? FindTreeNames()
433 : std::vector<std::string>(fFileNames.size(), std::string(treename))),
434 fFriendInfo()
435{
436}
437
438std::vector<std::string> GetFilesFromTree(TTree &tree)
439{
440 std::vector<std::string> filenames;
441
442 const bool isChain = tree.IsA() == TChain::Class();
443 if (isChain) {
444 TObjArray *filelist = static_cast<TChain &>(tree).GetListOfFiles();
445 const auto nFiles = filelist->GetEntries();
446 if (nFiles == 0)
447 throw std::runtime_error("The provided chain of files is empty");
448 filenames.reserve(nFiles);
449 for (auto f : *filelist)
450 filenames.emplace_back(f->GetTitle());
451 } else {
452 TFile *f = tree.GetCurrentFile();
453 if (!f) {
454 const auto msg = "The specified TTree is not linked to any file, in-memory-only trees are not supported.";
455 throw std::runtime_error(msg);
456 }
457
458 filenames.emplace_back(f->GetName());
459 }
460
461 return filenames;
462}
463
464////////////////////////////////////////////////////////////////////////
465/// Constructor based on a TTree and a TEntryList.
466/// \param[in] tree Tree or chain of files containing the tree to process.
467/// \param[in] entries List of entry numbers to process.
469 : fFileNames(GetFilesFromTree(tree)), fTreeNames(ROOT::Internal::GetTreeFullPaths(tree)), fEntryList(entries),
470 fFriendInfo(GetFriendInfo(tree))
471{
472}
473
474////////////////////////////////////////////////////////////////////////
475/// Constructor based on a TTree.
476/// \param[in] tree Tree or chain of files containing the tree to process.
478
479//////////////////////////////////////////////////////////////////////////////
480/// Process the entries of a TTree in parallel. The user-provided function
481/// receives a TTreeReader which can be used to iterate on a subrange of
482/// entries
483/// ~~~{.cpp}
484/// TTreeProcessorMT::Process([](TTreeReader& readerSubRange) {
485/// // Select branches to read
486/// while (readerSubRange.Next()) {
487/// // Use content of current entry
488/// }
489/// });
490/// ~~~
491/// The user needs to be aware that each of the subranges can potentially
492/// be processed in parallel. This means that the code of the user function
493/// should be thread safe.
494///
495/// \param[in] func User-defined function that processes a subrange of entries
497{
498 const std::vector<Internal::NameAlias> &friendNames = fFriendInfo.fFriendNames;
499 const std::vector<std::vector<std::string>> &friendFileNames = fFriendInfo.fFriendFileNames;
500
501 // If an entry list or friend trees are present, we need to generate clusters with global entry numbers,
502 // so we do it here for all files.
503 const bool hasFriends = !friendNames.empty();
504 const bool hasEntryList = fEntryList.GetN() > 0;
505 const bool shouldRetrieveAllClusters = hasFriends || hasEntryList;
506 const auto clustersAndEntries =
508 const auto &clusters = clustersAndEntries.first;
509 const auto &entries = clustersAndEntries.second;
510
511 // Retrieve number of entries for each file for each friend tree
512 const auto friendEntries =
513 hasFriends ? Internal::GetFriendEntries(friendNames, friendFileNames) : std::vector<std::vector<Long64_t>>{};
514
515 TThreadExecutor pool;
516 // Parent task, spawns tasks that process each of the entry clusters for each input file
517 using Internal::EntryCluster;
518 auto processFile = [&](std::size_t fileIdx) {
519 // theseFiles contains either all files or just the single file to process
520 const auto &theseFiles = shouldRetrieveAllClusters ? fFileNames : std::vector<std::string>({fFileNames[fileIdx]});
521 // either all tree names or just the single tree to process
522 const auto &theseTrees = shouldRetrieveAllClusters ? fTreeNames : std::vector<std::string>({fTreeNames[fileIdx]});
523 // Evaluate clusters (with local entry numbers) and number of entries for this file, if needed
524 const auto theseClustersAndEntries =
525 shouldRetrieveAllClusters ? Internal::ClustersAndEntries{} : Internal::MakeClusters(theseTrees, theseFiles);
526
527 // All clusters for the file to process, either with global or local entry numbers
528 const auto &thisFileClusters = shouldRetrieveAllClusters ? clusters[fileIdx] : theseClustersAndEntries.first[0];
529
530 // Either all number of entries or just the ones for this file
531 const auto &theseEntries =
532 shouldRetrieveAllClusters ? entries : std::vector<Long64_t>({theseClustersAndEntries.second[0]});
533
534 auto processCluster = [&](const Internal::EntryCluster &c) {
535 std::unique_ptr<TTreeReader> reader;
536 std::unique_ptr<TEntryList> elist;
537 std::tie(reader, elist) = fTreeView->GetTreeReader(c.start, c.end, theseTrees, theseFiles, fFriendInfo,
538 fEntryList, theseEntries, friendEntries);
539 func(*reader);
540 };
541
542 pool.Foreach(processCluster, thisFileClusters);
543 };
544
545 std::vector<std::size_t> fileIdxs(fFileNames.size());
546 std::iota(fileIdxs.begin(), fileIdxs.end(), 0u);
547
548 // Enable this IMT use case (activate its locks)
550
551 pool.Foreach(processFile, fileIdxs);
552}
553
554////////////////////////////////////////////////////////////////////////
555/// \brief Sets the maximum number of tasks created per file, per worker.
556/// \return The maximum number of tasks created per file, per worker
558{
560}
561
562////////////////////////////////////////////////////////////////////////
563/// \brief Sets the maximum number of tasks created per file, per worker.
564/// \param[in] maxTasksPerFile Name of the file containing the tree to process.
565///
566/// This allows to create a reasonable number of tasks even if any of the
567/// processed files features a bad clustering, for example with a lot of
568/// entries and just a few entries per cluster.
569void TTreeProcessorMT::SetMaxTasksPerFilePerWorker(unsigned int maxTasksPerFile)
570{
571 fgMaxTasksPerFilePerWorker = maxTasksPerFile;
572}
void Class()
Definition: Class.C:29
#define f(i)
Definition: RSha256.hxx:104
#define c(i)
Definition: RSha256.hxx:101
long long Long64_t
Definition: RtypesCore.h:69
#define gDirectory
Definition: TDirectory.h:223
void Error(const char *location, const char *msgfmt,...)
char name[80]
Definition: TGX11.cxx:109
std::vector< std::string > GetFilesFromTree(TTree &tree)
std::vector< std::string > CheckAndConvert(const std::vector< std::string_view > &views)
std::pair< std::unique_ptr< TTreeReader >, std::unique_ptr< TEntryList > > TreeReaderEntryListPair
std::unique_ptr< TChain > fChain
Chain on which to operate.
std::vector< std::unique_ptr< TChain > > fFriends
Friends of the tree/chain.
void MakeChain(const std::vector< std::string > &treeName, const std::vector< std::string > &fileNames, const FriendInfo &friendInfo, const std::vector< Long64_t > &nEntries, const std::vector< std::vector< Long64_t > > &friendEntries)
Construct fChain, also adding friends if needed and injecting knowledge of offsets if available.
std::unique_ptr< TTreeReader > MakeReader(Long64_t start, Long64_t end)
TreeReaderEntryListPair MakeReaderWithEntryList(TEntryList &globalList, Long64_t start, Long64_t end)
TreeReaderEntryListPair GetTreeReader(Long64_t start, Long64_t end, const std::vector< std::string > &treeName, const std::vector< std::string > &fileNames, const FriendInfo &friendInfo, TEntryList entryList, const std::vector< Long64_t > &nEntries, const std::vector< std::vector< Long64_t > > &friendEntries)
Get a TTreeReader for the current tree of this view.
This class provides a simple interface to execute the same task multiple times in parallel,...
void Foreach(F func, unsigned nTimes, unsigned nChunks=0)
Execute func (with no arguments) nTimes in parallel.
A class to process the entries of a TTree in parallel.
const std::vector< std::string > fTreeNames
TTree names (always same size and ordering as fFileNames)
static unsigned int GetMaxTasksPerFilePerWorker()
Sets the maximum number of tasks created per file, per worker.
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 void SetMaxTasksPerFilePerWorker(unsigned int m)
Sets the maximum number of tasks created per file, per worker.
static unsigned int fgMaxTasksPerFilePerWorker
TTreeProcessorMT(std::string_view filename, std::string_view treename="")
Constructor based on a file name.
const TEntryList fEntryList
User-defined selection of entry numbers to be processed, empty if none was provided.
ROOT::TThreadedObject< ROOT::Internal::TTreeView > fTreeView
! Thread-local TreeViews
void Process(std::function< void(TTreeReader &)> func)
Process the entries of a TTree in parallel.
const Internal::FriendInfo fFriendInfo
A chain is a collection of files containing TTree objects.
Definition: TChain.h:34
TObjArray * GetListOfFiles() const
Definition: TChain.h:108
Small helper to keep current directory context.
Definition: TDirectory.h:41
A List of entry numbers in a TTree or TChain.
Definition: TEntryList.h:26
virtual TList * GetLists() const
Definition: TEntryList.h:73
virtual Long64_t GetN() const
Definition: TEntryList.h:75
A ROOT file is a suite of consecutive data records (TKey instances) with a well defined format.
Definition: TFile.h:48
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:3923
A TFriendElement TF describes a TTree object TF in a file.
Book space in a file, create I/O buffers, to fill them, (un)compress them.
Definition: TKey.h:24
virtual const char * GetName() const
Returns name of object.
Definition: TNamed.h:47
An array of TObjects.
Definition: TObjArray.h:37
Int_t GetEntries() const
Return the number of objects in array (i.e.
Definition: TObjArray.cxx:522
Mother of all ROOT objects.
Definition: TObject.h:37
@ kMustCleanup
if object destructor must call RecursiveRemove()
Definition: TObject.h:60
A simple, robust and fast interface to read values from ROOT columnar datasets such as TTree,...
Definition: TTreeReader.h:43
A TTree represents a columnar dataset.
Definition: TTree.h:72
virtual TClusterIterator GetClusterIterator(Long64_t firstentry)
Return an iterator over the cluster of baskets starting at firstentry.
Definition: TTree.cxx:5326
virtual Long64_t GetEntries() const
Definition: TTree.h:450
basic_string_view< char > string_view
static std::vector< std::string > GetTreeFullPaths(const TTree &tree)
Return the full path of the TTree or the trees in the TChain.
std::pair< std::vector< std::vector< EntryCluster > >, std::vector< Long64_t > > ClustersAndEntries
Return a vector of cluster boundaries for the given tree and files.
static std::vector< std::vector< Long64_t > > GetFriendEntries(const std::vector< std::pair< std::string, std::string > > &friendNames, const std::vector< std::vector< std::string > > &friendFileNames)
Return a vector containing the number of entries of each file of each friend TChain.
static ClustersAndEntries MakeClusters(const std::vector< std::string > &treeNames, const std::vector< std::string > &fileNames)
void function(const Char_t *name_, T fun, const Char_t *docstring=0)
Definition: RExports.h:151
VSD Structures.
Definition: StringConv.hxx:21
UInt_t GetImplicitMTPoolSize()
Returns the size of the pool used for implicit multi-threading.
Definition: TROOT.cxx:618
Definition: tree.py:1
std::vector< std::vector< std::string > > fFriendFileNames
Names of the files where each friend is stored.
std::vector< Internal::NameAlias > fFriendNames
Pairs of names and aliases of friend trees/chains.