DQMEDAnalyzer

DQMEDAnalyzerGlobalCache

Macros

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
#ifndef DQMServices_Core_DQMEDAnalyzer_h
#define DQMServices_Core_DQMEDAnalyzer_h

#include "FWCore/Framework/interface/stream/makeGlobal.h"

struct DQMEDAnalyzerGlobalCache;

// If we declare a global cache (which is not absolutely needed right now, but
// might be in the future), the framework will try to pass it to the
// constructor. But, we don't want to change all subsystem code whenever we
// change that implementation detail, so instead we hack the framework to not
// do that. See issue #27125.
namespace edm::stream::impl {
  template <typename T>
  T* makeStreamModule(edm::ParameterSet const& iPSet, DQMEDAnalyzerGlobalCache const* global) {
    return new T(iPSet);
  }
}  // namespace edm::stream::impl

#include "DQMServices/Core/interface/DQMStore.h"
#include "FWCore/Framework/interface/Event.h"
#include "FWCore/Framework/interface/Run.h"
#include "FWCore/ServiceRegistry/interface/Service.h"
#include "FWCore/Framework/interface/stream/EDProducer.h"
#include "FWCore/ParameterSet/interface/ParameterSet.h"
#include "DataFormats/Histograms/interface/DQMToken.h"

struct DQMEDAnalyzerGlobalCache {
  // slightly overkill for now, but we might want to putt the full DQMStore
  // here at some point.
  mutable std::mutex master_;
  mutable edm::EDPutTokenT<DQMToken> lumiToken_;
  mutable edm::EDPutTokenT<DQMToken> runToken_;
};

/**
 * The standard DQM module base.
 */
class DQMEDAnalyzer : public edm::stream::EDProducer<edm::GlobalCache<DQMEDAnalyzerGlobalCache>,
                                                     edm::EndRunProducer,
                                                     edm::EndLuminosityBlockProducer,
                                                     edm::Accumulator> {
public:
  typedef dqm::reco::DQMStore DQMStore;
  typedef dqm::reco::MonitorElement MonitorElement;

  virtual bool getCanSaveByLumi() { return true; }

  // framework calls in the order of invocation

  static std::unique_ptr<DQMEDAnalyzerGlobalCache> initializeGlobalCache(edm::ParameterSet const&) {
    return std::make_unique<DQMEDAnalyzerGlobalCache>();
  }

  DQMEDAnalyzer() {
    // for whatever reason we need the explicit `template` keyword here.
    runToken_ = this->template produces<DQMToken, edm::Transition::EndRun>("DQMGenerationRecoRun");
    lumiToken_ = this->template produces<DQMToken, edm::Transition::EndLuminosityBlock>("DQMGenerationRecoLumi");
    streamId_ = edm::StreamID::invalidStreamID().value();
  }

  void beginStream(edm::StreamID id) final {
    assert(streamId_ == edm::StreamID::invalidStreamID().value() || streamId_ == id.value());
    this->streamId_ = id.value();
    // now, since we can't access the global cache in the constructor (we
    // blocked that above to not expose the cache to the subsystem code,
    // we need to store the tokens here.
    // This also requires locking, since the streams will run in parallel.
    // See https://github.com/cms-sw/cmssw/issues/27291#issuecomment-505909101
    auto lock = std::scoped_lock(globalCache()->master_);
    if (globalCache()->runToken_.isUninitialized()) {
      globalCache()->lumiToken_ = lumiToken_;
      globalCache()->runToken_ = runToken_;
    }
  }

  void beginRun(edm::Run const& run, edm::EventSetup const& setup) final {
    // if we run booking multiple times because there are multiple runs in a
    // job, this is needed to make sure all existing MEs are in a valid state
    // before the booking code runs.
    edm::Service<DQMStore>()->initLumi(run.run(), /* lumi */ 0, meId());
    edm::Service<DQMStore>()->enterLumi(run.run(), /* lumi */ 0, meId());
    dqmBeginRun(run, setup);
    edm::Service<DQMStore>()->bookTransaction(
        [this, &run, &setup](DQMStore::IBooker& booker) {
          booker.cd();
          this->bookHistograms(booker, run, setup);
        },
        meId(),
        this->getCanSaveByLumi());
    edm::Service<DQMStore>()->initLumi(run.run(), /* lumi */ 0, meId());
    edm::Service<DQMStore>()->enterLumi(run.run(), /* lumi */ 0, meId());
  }

  void beginLuminosityBlock(edm::LuminosityBlock const& lumi, edm::EventSetup const& setup) final {
    edm::Service<DQMStore>()->initLumi(lumi.run(), lumi.luminosityBlock(), meId());
    edm::Service<DQMStore>()->enterLumi(lumi.run(), lumi.luminosityBlock(), meId());
  }

  void accumulate(edm::Event const& event, edm::EventSetup const& setup) final { analyze(event, setup); }

  void endLuminosityBlock(edm::LuminosityBlock const& lumi, edm::EventSetup const& setup) final {
    edm::Service<DQMStore>()->leaveLumi(lumi.run(), lumi.luminosityBlock(), meId());
  }

  static void globalEndLuminosityBlockProduce(edm::LuminosityBlock& lumi,
                                              edm::EventSetup const& setup,
                                              LuminosityBlockContext const* context) {
    lumi.emplace(context->global()->lumiToken_);
  }

  void endRun(edm::Run const& run, edm::EventSetup const& setup) final {
    edm::Service<DQMStore>()->leaveLumi(run.run(), /* lumi */ 0, meId());
  }
  static void globalEndRunProduce(edm::Run& run, edm::EventSetup const& setup, RunContext const* context) {
    run.emplace<DQMToken>(context->global()->runToken_);
  }

  static void globalEndJob(DQMEDAnalyzerGlobalCache const*) {}

  // methods to be implemented by the user, in order of invocation
  virtual void dqmBeginRun(edm::Run const&, edm::EventSetup const&) {}
  virtual void bookHistograms(DQMStore::IBooker&, edm::Run const&, edm::EventSetup const&) = 0;
  virtual void analyze(edm::Event const&, edm::EventSetup const&) {}

protected:
  edm::EDPutTokenT<DQMToken> runToken_;
  edm::EDPutTokenT<DQMToken> lumiToken_;
  unsigned int streamId_;
  uint64_t meId() const { return (((uint64_t)streamId_) << 32) + this->moduleDescription().id(); }
};

#endif  // DQMServices_Core_DQMEDAnalyzer_h