CMS 3D CMS Logo

RootOutputTree.cc
Go to the documentation of this file.
1 
2 #include "RootOutputTree.h"
3 
14 
15 #include "TBranch.h"
16 #include "TBranchElement.h"
17 #include "TCollection.h"
18 #include "TFile.h"
19 #include "TTreeCloner.h"
20 #include "Rtypes.h"
21 #include "RVersion.h"
22 
23 #include <limits>
24 
25 #include "tbb/task_arena.h"
26 
27 namespace edm {
28 
42  public:
44 
45  TTree* tree() const { return mytree_ ? mytree_.get() : tree_; }
46 
47  private:
48  DuplicateTreeSentry(DuplicateTreeSentry const&) = delete; // Disallow copying and moving
51  void operator()(TFile* iFile) const {
52  if (iFile) {
53  iFile->Close();
54  }
55  delete iFile;
56  }
57  };
58 
59  void dup() {
61  if (!pSLC.isAvailable()) {
62  return;
63  }
64  if (pSLC->sourceCacheHint() && *(pSLC->sourceCacheHint()) == "lazy-download") {
65  return;
66  }
67  if (!pSLC->sourceCloneCacheHint() || *(pSLC->sourceCloneCacheHint()) != "lazy-download") {
68  return;
69  }
70  edm::LogWarning("DuplicateTreeSentry") << "Re-opening file for fast-cloning";
71 
72  TFile* file = tree_->GetCurrentFile();
73  const TUrl* url = file->GetEndpointUrl();
74  if (!url) {
75  return;
76  }
77  file_.reset(TFile::Open(url->GetUrl(), "READWRAP")); // May throw an exception.
78  if (!file_) {
79  return;
80  }
81  mytree_.reset(dynamic_cast<TTree*>(file_->Get(tree_->GetName())));
82  if (!mytree_) {
83  return;
84  }
85  }
86 
91  std::unique_ptr<TFile, CloseBeforeDelete> file_;
92  TTree* tree_ = nullptr;
93  std::unique_ptr<TTree> mytree_ = nullptr;
94  };
95 
96  RootOutputTree::RootOutputTree(std::shared_ptr<TFile> filePtr,
97  BranchType const& branchType,
98  int splitLevel,
99  int treeMaxVirtualSize,
100  std::string const& processName)
101  : filePtr_(filePtr),
102  tree_(processName.empty()
103  ? makeTTree(filePtr.get(), BranchTypeToProductTreeName(branchType), splitLevel)
104  : makeTTree(filePtr.get(), BranchTypeToProductTreeName(branchType, processName), splitLevel)),
105  producedBranches_(),
106  readBranches_(),
107  auxBranches_(),
108  unclonedReadBranches_(),
109  clonedReadBranchNames_(),
110  currentlyFastCloning_(),
111  fastCloneAuxBranches_(false) {
112  if (treeMaxVirtualSize >= 0)
113  tree_->SetMaxVirtualSize(treeMaxVirtualSize);
114  }
115 
116  TTree* RootOutputTree::assignTTree(TFile* filePtr, TTree* tree) {
117  tree->SetDirectory(filePtr);
118  // Turn off autosaving because it is such a memory hog and we are not using
119  // this check-pointing feature anyway.
121  return tree;
122  }
123 
124  TTree* RootOutputTree::makeTTree(TFile* filePtr, std::string const& name, int splitLevel) {
125  TTree* tree = new TTree(name.c_str(), "", splitLevel);
126  if (!tree)
127  throw edm::Exception(errors::FatalRootError) << "Failed to create the tree: " << name << "\n";
128  if (tree->IsZombie())
129  throw edm::Exception(errors::FatalRootError) << "Tree: " << name << " is a zombie."
130  << "\n";
131 
132  return assignTTree(filePtr, tree);
133  }
134 
135  bool RootOutputTree::checkSplitLevelsAndBasketSizes(TTree* inputTree) const {
136  assert(inputTree != nullptr);
137 
138  // Do the split level and basket size match in the input and output?
139  for (auto const& outputBranch : readBranches_) {
140  if (outputBranch != nullptr) {
141  TBranch* inputBranch = inputTree->GetBranch(outputBranch->GetName());
142 
143  if (inputBranch != nullptr) {
144  if (inputBranch->GetSplitLevel() != outputBranch->GetSplitLevel() ||
145  inputBranch->GetBasketSize() != outputBranch->GetBasketSize()) {
146  return false;
147  }
148  }
149  }
150  }
151  return true;
152  }
153 
154  namespace {
155  bool checkMatchingBranches(TBranchElement* inputBranch, TBranchElement* outputBranch) {
156  if (inputBranch->GetStreamerType() != outputBranch->GetStreamerType()) {
157  return false;
158  }
159  TObjArray* inputArray = inputBranch->GetListOfBranches();
160  TObjArray* outputArray = outputBranch->GetListOfBranches();
161 
162  if (outputArray->GetSize() < inputArray->GetSize()) {
163  return false;
164  }
165  TIter iter(outputArray);
166  TObject* obj = nullptr;
167  while ((obj = iter.Next()) != nullptr) {
168  TBranchElement* outBranch = dynamic_cast<TBranchElement*>(obj);
169  if (outBranch) {
170  TBranchElement* inBranch = dynamic_cast<TBranchElement*>(inputArray->FindObject(outBranch->GetName()));
171  if (!inBranch) {
172  return false;
173  }
174  if (!checkMatchingBranches(inBranch, outBranch)) {
175  return false;
176  }
177  }
178  }
179  return true;
180  }
181  } // namespace
182 
183  bool RootOutputTree::checkIfFastClonable(TTree* inputTree) const {
184  if (inputTree == nullptr)
185  return false;
186 
187  // Do the sub-branches match in the input and output. Extra sub-branches in the input are OK for fast cloning, but not in the output.
188  for (auto const& outputBr : readBranches_) {
189  TBranchElement* outputBranch = dynamic_cast<TBranchElement*>(outputBr);
190  if (outputBranch != nullptr) {
191  TBranchElement* inputBranch = dynamic_cast<TBranchElement*>(inputTree->GetBranch(outputBranch->GetName()));
192  if (inputBranch != nullptr) {
193  // We have a matching top level branch. Do the recursive check on subbranches.
194  if (!checkMatchingBranches(inputBranch, outputBranch)) {
195  LogInfo("FastCloning") << "Fast Cloning disabled because a data member has been added to split branch: "
196  << inputBranch->GetName() << "\n.";
197  return false;
198  }
199  }
200  }
201  }
202  return true;
203  }
204 
205  bool RootOutputTree::checkEntriesInReadBranches(Long64_t expectedNumberOfEntries) const {
206  for (auto const& readBranch : readBranches_) {
207  if (readBranch->GetEntries() != expectedNumberOfEntries) {
208  return false;
209  }
210  }
211  return true;
212  }
213 
215  if (in->GetEntries() != 0) {
216  TObjArray* branches = tree_->GetListOfBranches();
217  // If any products were produced (not just event products), the EventAuxiliary will be modified.
218  // In that case, don't fast copy auxiliary branches. Remove them, and add back after fast copying.
219  std::map<Int_t, TBranch*> auxIndexes;
220  bool mustRemoveSomeAuxs = false;
221  if (!fastCloneAuxBranches_) {
222  for (auto const& auxBranch : auxBranches_) {
223  int auxIndex = branches->IndexOf(auxBranch);
224  assert(auxIndex >= 0);
225  auxIndexes.insert(std::make_pair(auxIndex, auxBranch));
226  branches->RemoveAt(auxIndex);
227  }
228  mustRemoveSomeAuxs = true;
229  }
230 
231  //Deal with any aux branches which can never be cloned
232  for (auto const& auxBranch : unclonedAuxBranches_) {
233  int auxIndex = branches->IndexOf(auxBranch);
234  assert(auxIndex >= 0);
235  auxIndexes.insert(std::make_pair(auxIndex, auxBranch));
236  branches->RemoveAt(auxIndex);
237  mustRemoveSomeAuxs = true;
238  }
239 
240  if (mustRemoveSomeAuxs) {
241  branches->Compress();
242  }
243 
244  DuplicateTreeSentry dupTree(in);
245  TTreeCloner cloner(
246  dupTree.tree(), tree_, option.c_str(), TTreeCloner::kNoWarnings | TTreeCloner::kIgnoreMissingTopLevel);
247 
248  if (!cloner.IsValid()) {
249  // Let's check why
250  static const char* okerror = "One of the export branch";
251  if (strncmp(cloner.GetWarning(), okerror, strlen(okerror)) == 0) {
252  // That's fine we will handle it;
253  } else {
254  throw edm::Exception(errors::FatalRootError) << "invalid TTreeCloner (" << cloner.GetWarning() << ")\n";
255  }
256  }
257  tree_->SetEntries(tree_->GetEntries() + in->GetEntries());
258  Service<RootHandlers> rootHandler;
259  rootHandler->ignoreWarningsWhileDoing([&cloner] { cloner.Exec(); });
260 
261  if (mustRemoveSomeAuxs) {
262  for (auto const& auxIndex : auxIndexes) {
263  // Add the auxiliary branches back after fast copying the rest of the tree.
264  Int_t last = branches->GetLast();
265  if (last >= 0) {
266  branches->AddAtAndExpand(branches->At(last), last + 1);
267  for (Int_t ind = last - 1; ind >= auxIndex.first; --ind) {
268  branches->AddAt(branches->At(ind), ind + 1);
269  };
270  branches->AddAt(auxIndex.second, auxIndex.first);
271  } else {
272  branches->Add(auxIndex.second);
273  }
274  }
275  }
276  }
277  }
278 
280  if (tree->GetNbranches() != 0) {
281  // This is required when Fill is called on individual branches
282  // in the TTree instead of calling Fill once for the entire TTree.
283  tree->SetEntries(-1);
284  }
285  setRefCoreStreamer(true);
286  tree->AutoSave("FlushBaskets");
287  }
288 
289  void RootOutputTree::fillTTree(std::vector<TBranch*> const& branches) {
290  for_all(branches, std::bind(&TBranch::Fill, std::placeholders::_1));
291  }
292 
294 
295  void RootOutputTree::maybeFastCloneTree(bool canFastClone,
296  bool canFastCloneAux,
297  TTree* tree,
298  std::string const& option) {
299  unclonedReadBranches_.clear();
300  clonedReadBranchNames_.clear();
301  currentlyFastCloning_ = canFastClone && !readBranches_.empty();
302  if (currentlyFastCloning_) {
303  fastCloneAuxBranches_ = canFastCloneAux;
305  for (auto const& branch : readBranches_) {
306  if (branch->GetEntries() == tree_->GetEntries()) {
307  clonedReadBranchNames_.insert(std::string(branch->GetName()));
308  } else {
309  unclonedReadBranches_.push_back(branch);
310  }
311  }
312  Service<JobReport> reportSvc;
313  reportSvc->reportFastClonedBranches(clonedReadBranchNames_, tree_->GetEntries());
314  }
315  }
316 
318  if (currentlyFastCloning_) {
324  } else {
325  // Isolate the fill operation so that IMT doesn't grab other large tasks
326  // that could lead to PoolOutputModule stalling
327  tbb::this_task_arena::isolate([&] { tree_->Fill(); });
328  }
329  }
330 
332  std::string const& className,
333  void const*& pProd,
334  int splitLevel,
335  int basketSize,
336  bool produced) {
339  TBranch* branch = tree_->Branch(branchName.c_str(), className.c_str(), &pProd, basketSize, splitLevel);
340  assert(branch != nullptr);
341  /*
342  if(pProd != nullptr) {
343  // Delete the product that ROOT has allocated.
344  WrapperBase const* edp = static_cast<WrapperBase const *>(pProd);
345  delete edp;
346  pProd = nullptr;
347  }
348 */
349  if (produced) {
350  producedBranches_.push_back(branch);
351  } else {
352  readBranches_.push_back(branch);
353  }
354  }
355 
357  // The TFile was just closed.
358  // Just to play it safe, zero all pointers to quantities in the file.
359  auxBranches_.clear();
360  unclonedAuxBranches_.clear();
361  producedBranches_.clear();
362  readBranches_.clear();
363  unclonedReadBranches_.clear();
364  tree_ = nullptr; // propagate_const<T> has no reset() function
365  filePtr_ = nullptr; // propagate_const<T> has no reset() function
366  }
367 } // namespace edm
edm::RootOutputTree::fastCloneAuxBranches_
bool fastCloneAuxBranches_
Definition: RootOutputTree.h:119
edm::RootOutputTree::unclonedReadBranches_
std::vector< TBranch * > unclonedReadBranches_
Definition: RootOutputTree.h:115
edm::RootOutputTree::producedBranches_
std::vector< TBranch * > producedBranches_
Definition: RootOutputTree.h:111
edm::DuplicateTreeSentry::tree
TTree * tree() const
Definition: RootOutputTree.cc:45
relmon_authenticated_wget.url
url
Definition: relmon_authenticated_wget.py:22
edm::RootOutputTree::fillTTree
static void fillTTree(std::vector< TBranch * > const &branches)
Definition: RootOutputTree.cc:289
MessageLogger.h
funct::false
false
Definition: Factorize.h:29
edm::DuplicateTreeSentry::CloseBeforeDelete::operator()
void operator()(TFile *iFile) const
Definition: RootOutputTree.cc:51
filterRecHits_cfg.splitLevel
splitLevel
Definition: filterRecHits_cfg.py:41
MicroEventContent_cff.branch
branch
Definition: MicroEventContent_cff.py:174
electrons_cff.branchName
branchName
Definition: electrons_cff.py:520
edm
HLT enums.
Definition: AlignableModifier.h:19
tree
Definition: tree.py:1
edm::DuplicateTreeSentry::tree_
TTree * tree_
Definition: RootOutputTree.cc:92
Algorithms.h
cms::cuda::assert
assert(be >=bs)
edm::BranchTypeToProductTreeName
std::string const & BranchTypeToProductTreeName(BranchType const &branchType)
Definition: BranchType.cc:95
edm::LogInfo
Log< level::Info, false > LogInfo
Definition: MessageLogger.h:125
edm::DuplicateTreeSentry::file_
std::unique_ptr< TFile, CloseBeforeDelete > file_
Definition: RootOutputTree.cc:91
edm::RootOutputTree::writeTTree
static void writeTTree(TTree *tree)
Definition: RootOutputTree.cc:279
edm::Service::isAvailable
bool isAvailable() const
Definition: Service.h:40
fileinputsource_cfi.option
option
Definition: fileinputsource_cfi.py:94
edm::LogWarning
Log< level::Warning, false > LogWarning
Definition: MessageLogger.h:122
edm::BranchType
BranchType
Definition: BranchType.h:11
edm::RootOutputTree::checkSplitLevelsAndBasketSizes
bool checkSplitLevelsAndBasketSizes(TTree *inputTree) const
Definition: RootOutputTree.cc:135
edm::Exception
Definition: EDMException.h:77
edm::for_all
Func for_all(ForwardSequence &s, Func f)
wrapper for std::for_each
Definition: Algorithms.h:14
edm::DuplicateTreeSentry::mytree_
std::unique_ptr< TTree > mytree_
Definition: RootOutputTree.cc:93
EDMException.h
edm::RootOutputTree::assignTTree
static TTree * assignTTree(TFile *file, TTree *tree)
Definition: RootOutputTree.cc:116
edm::RootOutputTree::tree_
edm::propagate_const< TTree * > tree_
Definition: RootOutputTree.h:109
dqmdumpme.last
last
Definition: dqmdumpme.py:56
edm::DuplicateTreeSentry::operator=
DuplicateTreeSentry & operator=(DuplicateTreeSentry const &)=delete
edm::RootOutputTree::unclonedAuxBranches_
std::vector< TBranch * > unclonedAuxBranches_
Definition: RootOutputTree.h:114
RefCoreStreamer.h
edm::RootOutputTree::maybeFastCloneTree
void maybeFastCloneTree(bool canFastClone, bool canFastCloneAux, TTree *tree, std::string const &option)
Definition: RootOutputTree.cc:295
edm::errors::FatalRootError
Definition: EDMException.h:51
Service.h
edm::BranchDescription::invalidSplitLevel
static const int invalidSplitLevel
Definition: BranchDescription.h:34
edm::SiteLocalConfig::sourceCloneCacheHint
virtual std::string const * sourceCloneCacheHint() const =0
edm::RootOutputTree::readBranches_
std::vector< TBranch * > readBranches_
Definition: RootOutputTree.h:112
edm::RootOutputTree::RootOutputTree
RootOutputTree(std::shared_ptr< TFile > filePtr, BranchType const &branchType, int splitLevel, int treeMaxVirtualSize, std::string const &processName=std::string())
Definition: RootOutputTree.cc:96
edm::RootOutputTree::fastCloneTTree
void fastCloneTTree(TTree *in, std::string const &option)
Definition: RootOutputTree.cc:214
edm::RootOutputTree::checkIfFastClonable
bool checkIfFastClonable(TTree *inputTree) const
Definition: RootOutputTree.cc:183
edm::RootOutputTree::clonedReadBranchNames_
std::set< std::string > clonedReadBranchNames_
Definition: RootOutputTree.h:117
getGTfromDQMFile.obj
obj
Definition: getGTfromDQMFile.py:32
geometryDiff.file
file
Definition: geometryDiff.py:13
edm::RootOutputTree::makeTTree
static TTree * makeTTree(TFile *filePtr, std::string const &name, int splitLevel)
Definition: RootOutputTree.cc:124
BranchDescription.h
edm::RootOutputTree::writeTree
void writeTree()
Definition: RootOutputTree.cc:293
SiStripPI::max
Definition: SiStripPayloadInspectorHelper.h:169
recoMuon::in
Definition: RecoMuonEnumerators.h:6
edm::get
T const & get(Event const &event, InputTag const &tag) noexcept(false)
Definition: Event.h:679
edm::RootOutputTree::checkEntriesInReadBranches
bool checkEntriesInReadBranches(Long64_t expectedNumberOfEntries) const
Definition: RootOutputTree.cc:205
edm::Service
Definition: Service.h:30
RootOutputTree.h
AlCaHLTBitMon_QueryRunRegistry.string
string string
Definition: AlCaHLTBitMon_QueryRunRegistry.py:256
HcalObjRepresent::Fill
void Fill(HcalDetId &id, double val, std::vector< TH2F > &depth)
Definition: HcalObjRepresent.h:1053
SimL1EmulatorRepack_CalouGT_cff.processName
processName
Definition: SimL1EmulatorRepack_CalouGT_cff.py:17
edm::RootOutputTree::tree
TTree const * tree() const
Definition: RootOutputTree.h:84
edm::DuplicateTreeSentry
Definition: RootOutputTree.cc:41
edm::RootOutputTree::filePtr_
edm::propagate_const< std::shared_ptr< TFile > > filePtr_
Definition: RootOutputTree.h:108
relativeConstraints.empty
bool empty
Definition: relativeConstraints.py:46
Exception
Definition: hltDiff.cc:245
edm::BranchDescription::invalidBasketSize
static const int invalidBasketSize
Definition: BranchDescription.h:35
edm::DuplicateTreeSentry::DuplicateTreeSentry
DuplicateTreeSentry(TTree *tree)
Definition: RootOutputTree.cc:43
Skims_PA_cff.name
name
Definition: Skims_PA_cff.py:17
edm::setRefCoreStreamer
void setRefCoreStreamer(bool resetAll=false)
Definition: RefCoreStreamer.cc:83
RootHandlers.h
edm::SiteLocalConfig::sourceCacheHint
virtual std::string const * sourceCacheHint() const =0
className
std::string className(const T &t)
Definition: ClassName.h:31
edm::DuplicateTreeSentry::CloseBeforeDelete
Definition: RootOutputTree.cc:50
JobReport.h
edm::RootOutputTree::close
void close()
Definition: RootOutputTree.cc:356
edm::RootOutputTree::auxBranches_
std::vector< TBranch * > auxBranches_
Definition: RootOutputTree.h:113
edm::DuplicateTreeSentry::dup
void dup()
Definition: RootOutputTree.cc:59
edm::RootOutputTree::addBranch
void addBranch(std::string const &branchName, std::string const &className, void const *&pProd, int splitLevel, int basketSize, bool produced)
Definition: RootOutputTree.cc:331
edm::RootOutputTree::fillTree
void fillTree()
Definition: RootOutputTree.cc:317
SiteLocalConfig.h
edm::RootOutputTree::currentlyFastCloning_
bool currentlyFastCloning_
Definition: RootOutputTree.h:118