CMS 3D CMS Logo

DQMStore.cc
Go to the documentation of this file.
1 // silence deprecation warnings for the DQMStore itself.
2 #define DQM_DEPRECATED
7 #include <string>
8 #include <regex>
9 #include <csignal>
10 
11 #include <execinfo.h>
12 #include <cxxabi.h>
13 
14 namespace dqm::implementation {
15 
17  if (cwd_.empty()) {
18  return "";
19  } else {
20  // strip trailing slash.
21  // This is inefficient and error prone (callers need to do the same
22  // branching to re-add the "/"!) but some legacy code expects it like
23  // that and is to complicated to change.
24  assert(cwd_[cwd_.size() - 1] == '/');
25  auto pwd = cwd_.substr(0, cwd_.size() - 1);
26  return pwd;
27  }
28  }
31  void NavigatorBase::goUp() { cd(cwd_ + ".."); }
35  assert(this);
36  cwd_ = path.getDirname();
37  }
38 
40  store_ = store;
41  scope_ = MonitorElementData::Scope::JOB;
42  }
43 
45 
47  auto oldscope = scope_;
48  scope_ = newscope;
49  return oldscope;
50  }
52  auto oldid = moduleID_;
53  moduleID_ = moduleID;
54  return oldid;
55  }
56 
58  auto oldrunlumi = runlumi_;
59  runlumi_ = runlumi;
60  return oldrunlumi;
61  }
62 
65  std::function<TH1*()> makeobject,
66  bool forceReplace /* = false */) {
70 
71  // We should check if there is a local ME for this module and name already.
72  // However, it is easier to do that in putME().
73 
75  store_->printTrace("Booking " + std::string(name) + (me ? " (existing)" : " (new)"));
76 
77  if (me == nullptr) {
78  // no existing global ME found. We need to instantiate one, and put it
79  // into the DQMStore. This will typically be a prototype, unless run and
80  // lumi are set and we proces a legacy booking call.
81  TH1* th1 = makeobject();
82  MonitorElementData medata;
83  medata.key_.path_ = path;
84  medata.key_.kind_ = kind;
85  medata.key_.scope_ = this->scope_;
86 
87  // will be (0,0) ( = prototype) in the common case.
88  // This branching is for harvesting, where we have run/lumi in the booker.
89  if (this->scope_ == MonitorElementData::Scope::JOB) {
90  medata.key_.id_ = edm::LuminosityBlockID();
91  } else if (this->scope_ == MonitorElementData::Scope::RUN) {
92  medata.key_.id_ = edm::LuminosityBlockID(this->runlumi_.run(), 0);
93  } else if (this->scope_ == MonitorElementData::Scope::LUMI) {
94  // In the messy case of legacy-booking a LUMI ME in beginRun (or
95  // similar), where we don't have a valid lumi number yet, make sure to
96  // book a prototype instead.
97  if (this->runlumi_.run() != 0 && this->runlumi_.luminosityBlock() != 0) {
98  medata.key_.id_ = this->runlumi_;
99  } else {
100  medata.key_.id_ = edm::LuminosityBlockID();
101  }
102  } else {
103  assert(!"Illegal scope");
104  }
105 
106  medata.value_.object_ = std::unique_ptr<TH1>(th1);
107  MonitorElement* me_ptr = new MonitorElement(std::move(medata));
108  me = store_->putME(me_ptr);
109  } else {
110  if (forceReplace) {
111  TH1* th1 = makeobject();
112  assert(th1);
113  store_->debugTrackME("bookME (forceReplace)", nullptr, me);
114  // surgically replace Histogram
115  me->switchObject(std::unique_ptr<TH1>(th1));
116  }
117  }
118 
119  // me now points to a global ME owned by the DQMStore.
120  assert(me);
121 
122  // each booking call returns a unique "local" ME, which the DQMStore keeps
123  // in a container associated with the module (and potentially run, for
124  // DQMGlobalEDAnalyzer). This will later be update to point to different
125  // MEData (kept in a global ME) as needed.
126  // putME creates the local ME object as needed.
127  auto localme = store_->putME(me, this->moduleID_);
128  // me now points to a local ME owned by the DQMStore.
129  assert(localme);
130 
131  if (this->moduleID_ == 0) {
132  // this is a legacy/global/harvesting booking. In this case, we return
133  // the global directly. It is not advisable to hold this pointer, as we
134  // may delete the global ME later, but we promise to keep it valid for
135  // the entire job if there are no concurrent runs/lumis. (see
136  // assertLegacySafe option).
137  // We still created a local ME, so we can drive the lumi-changing for
138  // legacy modules in watchPreGlobalBeginLumi.
139  store_->debugTrackME("bookME (legacy)", localme, me);
140  return me;
141  } else {
142  // the normal case.
143  store_->debugTrackME("bookME (normal)", localme, me);
144  return localme;
145  }
146  }
147 
149  auto lock = std::scoped_lock(this->booking_mutex_);
150  assert(me);
151  auto existing_new = globalMEs_[me->getRunLumi()].insert(me);
152  if (existing_new.second == true) {
153  // successfully inserted, return new object
154  debugTrackME("putME (global)", nullptr, me);
155  return me;
156  } else {
157  // already present, return old object
158  delete me;
159  assert(!"Currently, this should never happen.");
160  return *(existing_new.first);
161  }
162  }
163 
165  auto lock = std::scoped_lock(this->booking_mutex_);
166  assert(me);
167  auto& localmes = localMEs_[moduleID];
168  auto existing = localmes.find(me);
169  if (existing == localmes.end()) {
170  // insert new local ME
171  MonitorElement* local_me = new MonitorElement(me);
172  auto existing_new = localmes.insert(local_me);
173  // successfully inserted, return new object
174  assert(existing_new.second == true); // insert successful
175  debugTrackME("putME (local, new)", local_me, me);
176  return local_me;
177  } else {
178  // already present, return old object
179  auto local_me = *existing;
180  edm::LogInfo("DQMStore") << "ME " << me->getFullname() << " booked twice in the same module.";
181  // the existing local ME might not have data attached (e.g. in 2nd run)
182  // in that case, we attach the global ME provided by booking above.
183  // This may be a prototype or of a random run/lumi, but it ensures that
184  // even LUMI histos are always valid after booking (as we promise for
185  // legacy modules -- for sequential runs/lumis, there is only ever one
186  // global ME, and the local one points to it).
187  if (!local_me->isValid()) {
188  local_me->switchData(me);
189  }
190  debugTrackME("putME (local, existing)", local_me, me);
191  return local_me;
192  }
193  }
194 
195  template <typename MELIKE>
197  auto lock = std::scoped_lock(this->booking_mutex_);
198  for (auto& [runlumi, meset] : this->globalMEs_) {
199  auto it = meset.find(path);
200  if (it != meset.end()) {
201  debugTrackME("findME (found)", nullptr, *it);
202  // no guarantee on which ME we return here -- only that clone'ing this
203  // would give a valid ME for that path.
204  return *it;
205  }
206  }
207  return nullptr;
208  }
209 
210  void DQMStore::printTrace(std::string const& message) {
211  if (verbose_ < 3)
212  return;
213  edm::LogWarning("DQMStoreBooking").log([&](auto& logger) {
214  std::regex s_rxtrace{"(.*)\\((.*)\\+0x.*\\).*(\\[.*\\])"};
215  std::regex s_rxself{"^[^()]*dqm::implementation::.*|^[^()]*edm::.*|.*edm::convertException::wrap.*"};
216 
217  void* array[10];
218  size_t size;
219  char** strings;
220  int demangle_status = 0;
221  std::vector<std::string> clean_trace;
222 
223  // glibc/libgcc backtrace functionality, declared in execinfo.h.
224  size = backtrace(array, 10);
225  strings = backtrace_symbols(array, size);
226 
227  size_t level = 1;
228  char* demangled = nullptr;
229  for (; level < size; ++level) {
230  std::cmatch match;
231  bool ok = std::regex_match(strings[level], match, s_rxtrace);
232 
233  if (!ok) {
234  edm::LogWarning("DQMStoreBacktrace") << "failed match" << level << strings[level];
235  continue;
236  }
237 
238  if (match[2].length() == 0) {
239  // no symbol, ignore.
240  continue;
241  }
242 
243  // demangle name to human readable form
244  demangled = abi::__cxa_demangle(std::string(match[2]).c_str(), nullptr, nullptr, &demangle_status);
245  if (!demangled || demangle_status != 0) {
246  edm::LogWarning("DQMStoreBacktrace") << "failed demangle! status " << demangle_status << " on " << match[2];
247  continue;
248  }
249 
250  if (std::regex_match(demangled, s_rxself)) {
251  // ignore framework/internal methods
252  free(demangled);
253  demangled = nullptr;
254  continue;
255  } else {
256  // keep the demangled name and the address.
257  // The address can be resolved to a line number in gdb attached to
258  // the process, using `list *0x<addr>`, but it can only be done in
259  // the running process and we can"t easily do it in this code.
260  clean_trace.push_back(std::string(demangled) + std::string(match[3]));
261  free(demangled);
262  demangled = nullptr;
263  }
264  }
265 
266  if (!clean_trace.empty()) {
267  logger << message << " at ";
268  for (auto const& s : clean_trace) {
269  logger << s << "; ";
270  }
271  } else {
272  logger << message << " : failed to collect stack trace.";
273  }
274 
275  free(strings);
276  });
277  }
278 
279  void DQMStore::debugTrackME(const char* message, MonitorElement* me_local, MonitorElement* me_global) const {
280  const char* scopename[] = {"INVALID", "JOB", "RUN", "LUMI"};
281  if (!this->trackME_.empty() && (me_local || me_global)) {
282  std::string name = me_global ? me_global->getFullname() : me_local->getFullname();
283  if (name.find(this->trackME_) != std::string::npos) {
284  edm::LogWarning("DQMStoreTrackME").log([&](auto& logger) {
285  logger << message << " for " << name << "(" << me_local << "," << me_global << ")";
286  auto writeme = [&](MonitorElement* me) {
287  if (me->isValid()) {
288  logger << " " << me->getRunLumi() << " scope " << scopename[me->getScope()];
289  if (me->kind() >= MonitorElement::Kind::TH1F) {
290  logger << " entries " << me->getEntries();
291  } else if (me->kind() == MonitorElement::Kind::STRING) {
292  logger << " value " << me->getStringValue();
293  } else if (me->kind() == MonitorElement::Kind::REAL) {
294  logger << " value " << me->getFloatValue();
295  } else if (me->kind() == MonitorElement::Kind::INT) {
296  logger << " value " << me->getIntValue();
297  }
298  } else {
299  logger << " (invalid)";
300  }
301  };
302  if (me_local) {
303  logger << " local:";
304  writeme(me_local);
305  }
306  if (me_global) {
307  logger << " global:";
308  writeme(me_global);
309  }
310  });
311  // A breakpoint can be useful here.
312  //std::raise(SIGINT);
313  }
314  }
315  }
316 
318  // This is specifically for DQMRootSource, or other input modules. These
319  // are special in that they use the legacy interface (no moduleID, no local
320  // MEs) but need to be able to handle concurrent lumisections correctly.
321  // The logic is very similar to that in enterLumi; this is enterLumi for
322  // Input Modules.
323  auto lock = std::scoped_lock(this->booking_mutex_);
324  auto existing = this->get(key);
325  if (existing) {
326  // exactly matching ME found, needs merging with the new data.
327  debugTrackME("findOrRecycle (found)", nullptr, existing);
328  return existing;
329  } // else
330 
331  // this is where we'd expect the ME.
332  auto& targetset = this->globalMEs_[key.id_];
333  // this is where we can get MEs to reuse.
334  auto& prototypes = this->globalMEs_[edm::LuminosityBlockID()];
335 
336  auto proto = prototypes.find(key.path_);
337  if (proto != prototypes.end()) {
338  MonitorElement* oldme = *proto;
339  assert(oldme->getScope() == key.scope_);
340  prototypes.erase(proto);
341  auto medata = oldme->release(); // destroy the ME, get its data.
342  // in this situation, nobody should be filling the ME concurrently.
343  medata->data_.key_.id_ = key.id_;
344  // We reuse the ME object here, even if we don't have to. This ensures
345  // that when running single-threaded without concurrent lumis/runs,
346  // the global MEs will also live forever and allow legacy usages.
347  oldme->switchData(medata);
348  auto result = targetset.insert(oldme);
349  assert(result.second); // was new insertion
350  auto newme = *result.first; // iterator to new ME
351  assert(oldme == newme); // recycling!
352  // newme is reset and ready to accept data.
353  debugTrackME("findOrRecycle (recycled)", nullptr, newme);
354  return newme;
355  } // else
356 
357  return nullptr;
358  }
359 
361  // Call initLumi for all modules, as a global operation.
362  auto lock = std::scoped_lock(this->booking_mutex_);
363  for (auto& kv : this->localMEs_) {
364  initLumi(run, lumi, kv.first);
365  }
366  }
367 
369  // Make sure global MEs for the run/lumi exist (depending on scope)
370 
371  auto lock = std::scoped_lock(this->booking_mutex_);
372 
373  // these are the MEs we need to update.
374  auto& localset = this->localMEs_[moduleID];
375  // this is where they need to point to.
376  // This could be a per-run or per-lumi set (depending on lumi == 0)
377  auto& targetset = this->globalMEs_[edm::LuminosityBlockID(run, lumi)];
378  // this is where we can get MEs to reuse.
379  auto& prototypes = this->globalMEs_[edm::LuminosityBlockID()];
380 
381  auto checkScope = [run, lumi](MonitorElementData::Scope scope) {
382  if (scope == MonitorElementData::Scope::JOB) {
383  return (run == 0 && lumi == 0);
384  } else if (scope == MonitorElementData::Scope::RUN) {
385  return (run != 0 && lumi == 0);
386  } else if (scope == MonitorElementData::Scope::LUMI) {
387  return (lumi != 0);
388  }
389  assert(!"Impossible Scope.");
390  return false;
391  };
392 
393  for (MonitorElement* me : localset) {
394  auto target = targetset.find(me); // lookup by path, thanks to MEComparison
395  if (target != targetset.end()) {
396  // we already have a ME, just use it!
397  debugTrackME("initLumi (existing)", nullptr, *target);
398  } else {
399  // look for a prototype to reuse.
400  auto proto = prototypes.find(me);
401  if (proto != prototypes.end()) {
402  // first, check if this ME needs updating at all. We can only check
403  // the scope once we have an actual global ME instance, the local ME
404  // might not have any data attached!
405  if (checkScope((*proto)->getScope()) == false) {
406  continue;
407  } // else
408  // reuse that.
409  MonitorElement* oldme = *proto;
410  prototypes.erase(proto);
411  auto medata = oldme->release(); // destroy the ME, get its data.
412  // in this situation, nobody should be filling the ME concurrently.
413  medata->data_.key_.id_ = edm::LuminosityBlockID(run, lumi);
414  // We reuse the ME object here, even if we don't have to. This ensures
415  // that when running single-threaded without concurrent lumis/runs,
416  // the global MEs will also live forever and allow legacy usages.
417  oldme->switchData(medata);
418  auto result = targetset.insert(oldme);
419  assert(result.second); // was new insertion
420  target = result.first; // iterator to new ME
421  debugTrackME("initLumi (reused)", nullptr, *target);
422  } else {
423  // no prototype available. That means we have concurrent Lumis/Runs,
424  // and need to make a clone now.
425  auto anyme = this->findME(me);
426  assert(anyme || !"local ME without any global ME!");
427  if (checkScope(anyme->getScope()) == false) {
428  continue;
429  } // else
430 
431  // whenever we clone global MEs, it is no longer safe to hold
432  // pointers to them.
434 
435  MonitorElementData newdata = anyme->cloneMEData();
436  newdata.key_.id_ = edm::LuminosityBlockID(run, lumi);
437  auto newme = new MonitorElement(std::move(newdata));
438  newme->Reset(); // we cloned a ME in use, not an empty prototype
439  auto result = targetset.insert(newme);
440  assert(result.second); // was new insertion
441  target = result.first; // iterator to new ME
442  debugTrackME("initLumi (allocated)", nullptr, *target);
443  }
444  }
445  }
446  }
447 
449  // point the local MEs for this module to these global MEs.
450 
451  // This needs to happen before we can use the global MEs for this run/lumi here.
452  // We could do it lazyly here, or eagerly globally in global begin lumi.
453  //initLumi(run, lumi, moduleID);
454 
455  auto lock = std::scoped_lock(this->booking_mutex_);
456 
457  // these are the MEs we need to update.
458  auto& localset = this->localMEs_[moduleID];
459  // this is where they need to point to.
460  auto& targetset = this->globalMEs_[edm::LuminosityBlockID(run, lumi)];
461 
462  // only for a sanity check
463  auto checkScope = [run, lumi](MonitorElementData::Scope scope) {
464  if (scope == MonitorElementData::Scope::JOB) {
465  return (run == 0 && lumi == 0);
466  } else if (scope == MonitorElementData::Scope::RUN) {
467  return (run != 0 && lumi == 0);
468  } else if (scope == MonitorElementData::Scope::LUMI) {
469  return (lumi != 0);
470  }
471  assert(!"Impossible Scope.");
472  return false;
473  };
474 
475  for (MonitorElement* me : localset) {
476  auto target = targetset.find(me); // lookup by path, thanks to MEComparison
477  if (target == targetset.end()) {
478  auto anyme = this->findME(me);
479  debugTrackME("enterLumi (nothingtodo)", me, nullptr);
480  assert(anyme && checkScope(anyme->getScope()) == false);
481  continue;
482  }
483  assert(target != targetset.end()); // initLumi should have taken care of this.
484  // now we have the proper global ME in the right place, point the local there.
485  // This is only safe if the name is exactly the same -- else it might corrupt
486  // the tree structure of the set!
487  me->switchData(*target);
488  debugTrackME("enterLumi (switchdata)", me, *target);
489  }
490  }
491 
493  // here, we remove the pointers in the local MEs. No deletion or recycling
494  // yet -- this has to happen after the output module had a chance to do its
495  // work. We just leave the global MEs where they are. This is purely an
496  // accounting step, the cleanup code has to check that nobody is using the
497  // ME any more, and here we make sure that is the case.
498 
499  auto lock = std::scoped_lock(this->booking_mutex_);
500 
501  // these are the MEs we need to update.
502  auto& localset = this->localMEs_[moduleID];
503 
504  auto checkScope = [run, lumi](MonitorElementData::Scope scope) {
505  if (scope == MonitorElementData::Scope::JOB) {
506  return (run == 0 && lumi == 0);
507  } else if (scope == MonitorElementData::Scope::RUN) {
508  return (run != 0 && lumi == 0);
509  } else if (scope == MonitorElementData::Scope::LUMI) {
510  return (lumi != 0);
511  }
512  assert(!"Impossible Scope.");
513  return false;
514  };
515 
516  for (MonitorElement* me : localset) {
517  // we have to be very careful with the ME here, it might not be backed by data at all.
518  if (me->isValid() && checkScope(me->getScope()) == true) {
519  // if we left the scope, simply release the data.
520  debugTrackME("leaveLumi (release)", me, nullptr);
521  me->release();
522  }
523  }
524  }
525 
527  // now, we are done with the lumi, no modules have any work to do on these
528  // MEs, and the output modules have saved this lumi/run. Remove/recycle
529  // the MEs here.
530 
531  auto lock = std::scoped_lock(this->booking_mutex_);
532 
533  // in case of end-job cleanup we need different logic because of the
534  // prototype set.
535  assert(run != 0 || lumi != 0);
536  auto& prototypes = this->globalMEs_[edm::LuminosityBlockID()];
537 
538  // these are the MEs we need to get rid of...
539  auto meset = std::set<MonitorElement*, MonitorElement::MEComparison>();
540  // ... we take them out first.
541  meset.swap(this->globalMEs_[edm::LuminosityBlockID(run, lumi)]);
542 
543  // temporary buffer for the MEs to recycle, we must not change the key
544  // while they are in a set.
545  auto torecycle = std::vector<MonitorElement*>();
546 
547  // here, this is only a sanity check and not functionally needed.
548  auto checkScope = [run, lumi](MonitorElementData::Scope scope) {
549  if (scope == MonitorElementData::Scope::JOB) {
550  assert(run == 0 && lumi == 0);
551  } else if (scope == MonitorElementData::Scope::RUN) {
552  assert(run != 0 && lumi == 0);
553  } else if (scope == MonitorElementData::Scope::LUMI) {
554  assert(lumi != 0);
555  } else {
556  assert(!"Impossible Scope.");
557  }
558  };
559 
560  for (MonitorElement* me : meset) {
561  assert(me->isValid()); // global MEs should always be valid.
562  checkScope(me->getScope()); // we should only see MEs of one scope here.
563  auto other = this->findME(me);
564  if (other) {
565  // we still have a global one, so we can just remove this.
566  debugTrackME("cleanupLumi (delete)", nullptr, me);
567  delete me;
568  } else {
569  // we will modify the ME, so it needs to be out of the set.
570  // use a temporary vector to be save.
571  debugTrackME("cleanupLumi (recycle)", nullptr, me);
572  torecycle.push_back(me);
573  }
574  }
575 
576  meset.clear();
577 
578  for (MonitorElement* me : torecycle) {
579  auto medata = me->release(); // destroy the ME, get its data.
580  medata->data_.key_.id_ = edm::LuminosityBlockID(); // prototype
581  // We reuse the ME object here, even if we don't have to. This ensures
582  // that when running single-threaded without concurrent lumis/runs,
583  // the global MEs will also live forever and allow legacy usages.
584  me->switchData(medata);
585  // reset here (not later) to still catch random legacy fill calls.
586  me->Reset();
587  auto result = prototypes.insert(me);
588  assert(result.second); // was new insertion, else findME should succeed
589  debugTrackME("cleanupLumi (reset)", nullptr, me);
590  }
591  }
592 
593  std::vector<dqm::harvesting::MonitorElement*> IGetter::getContents(std::string const& pathname) const {
594  auto lock = std::scoped_lock(store_->booking_mutex_);
595  std::vector<MonitorElement*> out;
598  for (auto& [runlumi, meset] : store_->globalMEs_) {
599  auto it = meset.lower_bound(path);
600  while (it != meset.end() && (*it)->getPathname() == path.getDirname()) {
601  store_->debugTrackME("getContents (match)", nullptr, *it);
602  out.push_back(*it);
603  ++it;
604  }
605  }
606  return out;
607  }
608 
609  std::vector<dqm::harvesting::MonitorElement*> IGetter::getAllContents(std::string const& pathname) const {
610  auto lock = std::scoped_lock(store_->booking_mutex_);
611  std::vector<MonitorElement*> out;
614  // make sure this is normalized by getting it from Path object.
615  auto path_str = path.getFullname();
616  for (auto& [runlumi, meset] : store_->globalMEs_) {
617  auto it = meset.lower_bound(path);
618  // rfind can be used as a prefix match.
619  while (it != meset.end() && (*it)->getPathname().rfind(path_str, 0) == 0) {
620  if (runlumi == edm::LuminosityBlockID() && (*it)->getScope() != MonitorElementData::Scope::JOB) {
621  // skip prototypes
622  } else {
623  store_->debugTrackME("getAllContents (match)", nullptr, *it);
624  out.push_back(*it);
625  }
626  ++it;
627  }
628  }
629  return out;
630  }
631  std::vector<dqm::harvesting::MonitorElement*> IGetter::getAllContents(std::string const& pathname,
632  uint32_t runNumber,
633  uint32_t lumi) const {
634  auto lock = std::scoped_lock(store_->booking_mutex_);
635  std::vector<MonitorElement*> out;
638  // make sure this is normalized by getting it from Path object.
639  auto path_str = path.getFullname();
640  auto const& meset = store_->globalMEs_[edm::LuminosityBlockID(runNumber, lumi)];
641  auto it = meset.lower_bound(path);
642 
643  // decide if the ME should be save din DQMIO based on the list provided
644  bool saveIt = true;
645 
646  // rfind can be used as a prefix match.
647  while (it != meset.end() && (*it)->getFullname().rfind(path_str, 0) == 0) {
648  if (store_->doSaveByLumi_ && not store_->MEsToSave_.empty()) {
649  for (std::vector<std::string>::const_iterator ipath = store_->MEsToSave_.begin();
650  ipath != store_->MEsToSave_.end();
651  ++ipath) {
652  std::string name = (*it)->getFullname();
653  if (name.find(*ipath) != std::string::npos) {
654  saveIt = true;
655  //std::cout<<name<<" compared to"<<ipath->data()<<std::endl;
656  break;
657  }
658  saveIt = false;
659  }
660  }
661 
662  store_->debugTrackME("getAllContents (run/lumi match)", nullptr, *it);
663  if (saveIt) {
664  out.push_back(*it);
665  if (store_->doSaveByLumi_)
666  store_->debugTrackME("getAllContents (run/lumi saved)", nullptr, *it);
667  }
668  ++it;
669  }
670  return out;
671  }
672 
676  // this only really makes sense if there is only one instance of this ME,
677  // but the signature of this method also only makes sense in that case.
678  return store_->findME(path);
679  }
680 
682  auto const& meset = store_->globalMEs_[key.id_];
683  auto it = meset.find(key.path_);
684  if (it != meset.end()) {
685  assert((*it)->getScope() == key.scope_);
686  store_->debugTrackME("get (key found)", nullptr, *it);
687  return *it;
688  }
689  return nullptr;
690  }
691 
693  auto result = this->get(path);
694  if (result == nullptr) {
695  throw cms::Exception("iGetter Error") << "ME " << path << " was requested but not found.";
696  }
697  return result;
698  }
699 
700  std::vector<std::string> IGetter::getSubdirs() const {
701  // This is terribly inefficient, esp. if this method is then used to
702  // recursively enumerate whatever getAllContents would return anyways.
703  // But that is fine, any such code should just use getAllContents instead.
704  std::set<std::string> subdirs;
705  for (auto me : this->getAllContents(this->cwd_)) {
706  const auto& name = me->getPathname();
707  auto subdirname = name.substr(this->cwd_.length(), std::string::npos);
708  auto dirname = subdirname.substr(0, subdirname.find('/'));
709  subdirs.insert(dirname);
710  }
711  std::vector<std::string> out;
712  for (const auto& dir : subdirs) {
713  if (dir.length() == 0)
714  continue;
715  out.push_back(this->cwd_ + dir);
716  }
717  return out;
718  }
719 
720  std::vector<std::string> IGetter::getMEs() const {
721  auto mes = this->getContents(this->cwd_);
722  std::vector<std::string> out;
723  out.reserve(mes.size());
724  for (auto me : mes) {
725  out.push_back(me->getName());
726  }
727  return out;
728  }
729 
730  bool IGetter::dirExists(std::string const& path) const {
731  // we don't claim this is fast.
732  return !this->getAllContents(path).empty();
733  }
734 
735  IGetter::IGetter(DQMStore* store) { store_ = store; }
736 
738 
740  verbose_ = pset.getUntrackedParameter<int>("verbose", 0);
741  assertLegacySafe_ = pset.getUntrackedParameter<bool>("assertLegacySafe", false);
742  doSaveByLumi_ = pset.getUntrackedParameter<bool>("saveByLumi", false);
743  MEsToSave_ = pset.getUntrackedParameter<std::vector<std::string>>("MEsToSave", std::vector<std::string>());
744  trackME_ = pset.getUntrackedParameter<std::string>("trackME", "");
745 
746  // Set lumi and run for legacy booking.
747  // This is no more than a guess with concurrent runs/lumis, but should be
748  // correct for purely sequential legacy stuff.
749  // Also reset Scope, such that legacy modules can expect it to be JOB.
750  // initLumi and leaveLumi are needed for all module types: these handle
751  // creating and deleting global MEs as needed, which has to happen even if
752  // a module does not see lumi transitions.
753  ar.watchPreGlobalBeginRun([this](edm::GlobalContext const& gc) {
754  this->setRunLumi(gc.luminosityBlockID());
755  this->initLumi(gc.luminosityBlockID().run(), /* lumi */ 0);
756  this->enterLumi(gc.luminosityBlockID().run(), /* lumi */ 0, /* moduleID */ 0);
757  this->setScope(MonitorElementData::Scope::JOB);
758  });
759  ar.watchPreGlobalBeginLumi([this](edm::GlobalContext const& gc) {
760  this->setRunLumi(gc.luminosityBlockID());
762  this->enterLumi(gc.luminosityBlockID().run(), gc.luminosityBlockID().luminosityBlock(), /* moduleID */ 0);
763  });
764  ar.watchPostGlobalEndRun([this](edm::GlobalContext const& gc) {
765  this->leaveLumi(gc.luminosityBlockID().run(), /* lumi */ 0, /* moduleID */ 0);
766  });
767  ar.watchPostGlobalEndLumi([this](edm::GlobalContext const& gc) {
768  this->leaveLumi(gc.luminosityBlockID().run(), gc.luminosityBlockID().luminosityBlock(), /* moduleID */ 0);
769  });
770 
771  // Trigger cleanup after writing. This is needed for all modules; we can
772  // only run the cleanup after all output modules have run.
773  ar.watchPostGlobalWriteLumi([this](edm::GlobalContext const& gc) {
775  });
777  [this](edm::GlobalContext const& gc) { this->cleanupLumi(gc.luminosityBlockID().run(), 0); });
778 
779  // no cleanup at end of job, we don't really need it.
780  }
781 
783 
785  LegacyIOHelper h(this);
786  // no run number passed, will save a flat ROOT file (rather than 'Run xxxxxx/.../Run Summary/...')
787  h.save(filename, path);
788  }
789 
791  bool overwrite,
792  std::string const& path,
793  std::string const& prepend,
794  OpenRunDirs stripdirs,
795  bool fileMustExist) {
796  assert(!"NIY");
797  }
798 
799 } // namespace dqm::implementation
DQMStore(edm::ParameterSet const &pset, edm::ActivityRegistry &)
Definition: DQMStore.cc:739
size
Write out results.
LuminosityBlockNumber_t luminosityBlock() const
virtual DQM_DEPRECATED MonitorElement * getElement(std::string const &path) const
Definition: DQMStore.cc:692
virtual void setCurrentFolder(std::string const &fullpath)
Definition: DQMStore.cc:32
virtual std::vector< std::string > getMEs() const
Definition: DQMStore.cc:720
virtual std::string pwd()
Definition: DQMStore.cc:16
edm::propagate_const< std::unique_ptr< TH1 > > object_
virtual edm::LuminosityBlockID setRunLumi(edm::LuminosityBlockID runlumi)
Definition: DQMStore.cc:57
virtual MonitorElementData::Scope setScope(MonitorElementData::Scope newscope)
Definition: DQMStore.cc:46
void watchPreGlobalBeginLumi(PreGlobalBeginLumi::slot_type const &iSlot)
virtual bool dirExists(std::string const &path) const
Definition: DQMStore.cc:730
void printTrace(std::string const &message)
Definition: DQMStore.cc:210
std::map< uint64_t, std::set< MonitorElement *, MonitorElement::MEComparison > > localMEs_
Definition: DQMStore.h:779
virtual MonitorElement * bookME(TString const &name, MonitorElementData::Kind kind, std::function< TH1 *()> makeobject, bool forceReplace=false)
Definition: DQMStore.cc:63
edm::LuminosityBlockID runlumi_
Definition: DQMStore.h:558
MonitorElementData::Scope scope_
Definition: DQMStore.h:556
assert(be >=bs)
unsigned int LuminosityBlockNumber_t
MonitorElement * findOrRecycle(MonitorElementData::Key const &)
Definition: DQMStore.cc:317
void leaveLumi(edm::RunNumber_t run, edm::LuminosityBlockNumber_t lumi, uint64_t moduleID)
Definition: DQMStore.cc:492
void initLumi(edm::RunNumber_t run, edm::LuminosityBlockNumber_t lumi)
Definition: DQMStore.cc:360
void enterLumi(edm::RunNumber_t run, edm::LuminosityBlockNumber_t lumi, uint64_t moduleID)
Definition: DQMStore.cc:448
std::recursive_mutex booking_mutex_
Definition: DQMStore.h:783
virtual std::vector< dqm::harvesting::MonitorElement * > getAllContents(std::string const &path) const
Definition: DQMStore.cc:609
IGetter(DQMStore *store)
Definition: DQMStore.cc:735
IBooker(DQMStore *store)
Definition: DQMStore.cc:39
void watchPostGlobalEndLumi(PostGlobalEndLumi::slot_type const &iSlot)
std::map< edm::LuminosityBlockID, std::set< MonitorElement *, MonitorElement::MEComparison > > globalMEs_
Definition: DQMStore.h:775
Definition: logger.py:1
virtual uint64_t setModuleID(uint64_t moduleID)
Definition: DQMStore.cc:51
LuminosityBlockID const & luminosityBlockID() const
Definition: GlobalContext.h:60
MonitorElementData::Scope getScope()
RunNumber_t run() const
void watchPreGlobalBeginRun(PreGlobalBeginRun::slot_type const &iSlot)
Log< level::Info, false > LogInfo
dqm::legacy::MonitorElement MonitorElement
Definition: DQMStore.h:20
demangled
Definition: symbols.py:70
std::string getFullname() const
get full name of ME including Pathname
unsigned long long uint64_t
Definition: Time.h:13
void watchPostGlobalWriteRun(PostGlobalWriteRun::slot_type const &iSlot)
MonitorElement * findME(MELIKE const &path)
Definition: DQMStore.cc:196
void watchPostGlobalEndRun(PostGlobalEndRun::slot_type const &iSlot)
virtual MonitorElement * get(std::string const &fullpath) const
Definition: DQMStore.cc:673
std::vector< std::string > MEsToSave_
Definition: DQMStore.h:795
MonitorElement * putME(MonitorElement *me)
Definition: DQMStore.cc:148
DQM_DEPRECATED void save(std::string const &filename, std::string const &path="")
Definition: DQMStore.cc:784
void watchPostGlobalWriteLumi(PostGlobalEndLumi::slot_type const &iSlot)
void cleanupLumi(edm::RunNumber_t run, edm::LuminosityBlockNumber_t lumi)
Definition: DQMStore.cc:526
std::pair< typename Association::data_type::first_type, double > match(Reference key, Association association, bool bestMatchByMaxValue)
Generic matching function.
Definition: Utils.h:10
unsigned int RunNumber_t
Log< level::Warning, false > LogWarning
The Signals That Services Can Subscribe To This is based on ActivityRegistry h
Helper function to determine trigger accepts.
Definition: Activities.doc:4
void debugTrackME(const char *message, MonitorElement *me_local, MonitorElement *me_global) const
Definition: DQMStore.cc:279
def move(src, dest)
Definition: eostools.py:511
DQM_DEPRECATED bool open(std::string const &filename, bool overwrite=false, std::string const &path="", std::string const &prepend="", OpenRunDirs stripdirs=KeepRunDirs, bool fileMustExist=true)
Definition: DQMStore.cc:790
virtual std::vector< dqm::harvesting::MonitorElement * > getContents(std::string const &path) const
Definition: DQMStore.cc:593
virtual DQM_DEPRECATED std::vector< std::string > getSubdirs() const
Definition: DQMStore.cc:700