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