Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate TestLegacy* DQM modules to edm::one::EDAnalyzer #40409

Merged
merged 1 commit into from
Jan 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions DQMServices/Core/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ There are six supported types of DQM modules:
- `DQMOneLumiEDAnalyzer` based on `edm::one::EDProducer`. Used when begin/end lumi transitions are needed. Blocks concurrent lumisections.
- `DQMGlobalEDAnalyzer` based on `edm::global::EDProducer`. Used for DQM@HLT and a few random other things. Cannot save per-lumi histograms (this is a conflict with the fact that HLT _typically_ saves _only_ per lumi histograms, see #28341).
- `DQMEDHarvester` based on `edm::one::EDProducer`. Used in harvesting jobs to manipulate histograms in lumi, run, and job transitions.
- `edm::EDAnalyzer` legacy modules. Can do filling and harvesting. Not safe to use in the presence of concurrent lumisections. Safe for multi-threaded running from the DQM framework side.
- `edm::one::EDAnalyzer<edm::one::SharedResources>` that explicitly access `edm::Service<DQMStore>`, hereafter referred to as "legacy modules". Can do filling and harvesting. Not safe to use in the presence of concurrent lumisections. Safe for multi-threaded running from the DQM framework side.

The `DQMStore` lives in CMSSW as a `edm::Service` singleton instance.

Expand Down Expand Up @@ -62,7 +62,7 @@ Data is archived for eternity by CMS computing in DQMIO format, in legacy ROOT f
DQM code runs in various places during CMS data processing. How much code runs, and how much processing time is spent doing DQM, varies by orders of magnitude. In rough order of amount of code and time spent, there are

- _RECO_: Processing step in all CMS offline processing (Prompt, Express, ReReco, Monte Carlo, RelVal) where DQM data is extracted from events ("map" in the Map-Reduce pattern). Data is split into an arbitrary number of jobs and processed out of order and massively parallel. Runs `DQM*EDAnalyzer`s, DQMIO output and uses multi-threaded setup of CMSSW (potentially with concurrent lumisections). Configured using the `DQM` or `VALIDATION` steps in `cmsDriver.py`. Typically, only (a fraction of) a single run is processed per job, but jobs processing multiple runs are possible (e.g. in run-dependent Monte Carlo).
- _HARVESTING_: Processing step in all CMS offline processing where data saved by the RECO step in DQMIO format is read and reduced into the final output ("reduce" in the Map-Reduce pattern). Full run data is available. Produces a legacy ROOT output file and uploads it to DQMGUI. Runs `DQMEDHarvester`s and legacy `edm::EDAnalyzer`s, the `DQMRootSource` and `DQMFileSaver`. Harvesting jobs run single-threaded and process all data in order. Typically, only one run is processed per job.
- _HARVESTING_: Processing step in all CMS offline processing where data saved by the RECO step in DQMIO format is read and reduced into the final output ("reduce" in the Map-Reduce pattern). Full run data is available. Produces a legacy ROOT output file and uploads it to DQMGUI. Runs `DQMEDHarvester`s and "legacy" `edm::one::EDAnalyzer`s, the `DQMRootSource` and `DQMFileSaver`. Harvesting jobs run single-threaded and process all data in order. Typically, only one run is processed per job.
- _DQMIO merge_: Between RECO and HARVESTING, DQMIO files are partially merged into bigger files. No plugins run in this step, only DQMIO input and output. The configuration for these jobs is `Configuration/DataProcessing/python/Merge.py`.
- _ALCARECO_: Like RECO, but on special data and with special code for AlCa. Saves data in `MEtoEDM` format (among others) using the `MEtoEDMConverter`. The DQM-relevant modules are on the `ALCA` step in `cmsDriver.py`.
- _ALCAHARVEST_: Like HARVESTING, but for ALCAPROMPT data in `MEtoEDM` format (produced by ALCARECO jobs), using `EDMtoMEConverter`. No guarantee of in-order processing. Multiple runs may be processed in one job producing one legacy output file (multi-run harvesting).
Expand Down Expand Up @@ -136,7 +136,7 @@ The `MonitorElement` can now be filled with data using the `Fill` call, similar
When a ME is booked, internally _global_ and _local_ MEs are created. This should be invisible to the user; the technical details are as follows:
- In the DQM API, we face the conflict that `MonitorElement` objects are held in the modules (so their life cycle has to match that of the module) but also represent histograms whose life cycle depends the data processed (run and lumi transitions). This caused conflicts since the introduction of multi-threading.
- The `DQMStore` resolves this conflict by representing each monitor element using (at least) two objects: A _local_ `MonitorElement`, that follows the module life cycle but does not own data, and a _global_ `MonitorElement` that owns histogram data but does not belong to any module. There may be multiple _local_ MEs for one _global_ ME if multiple modules fill the same histogram (`edm::stream` or even independent modules). There may be multiple _global_ MEs for the same histogram if there are concurrent lumisections.
- The live cycle of _local_ MEs is driven by callbacks from each of the module base classes (`enterLumi`, `leaveLumi`). For legacy `edm::EDAnalyzer`s, global begin/end run/lumi hooks are used, which only work as long as there are no concurrent lumisections. The _local_ MEs are kept in a set of containers indexed by the `moduleID`, with special value `0` for _all_ legacy modules and special values for `DQMGlobalEDAnalyzer`s, where the local MEs need to match the life cycle of the `runCache` (module id + run number), and `DQMEDAnalyzer`s, where the `streamID` is combined with the `moduleID` to get a unique identifier for each stream instance.
- The live cycle of _local_ MEs is driven by callbacks from each of the module base classes (`enterLumi`, `leaveLumi`). For "legacy" `edm::one::EDAnalyzer`s, global begin/end run/lumi hooks are used, which only work as long as there are no concurrent lumisections. The _local_ MEs are kept in a set of containers indexed by the `moduleID`, with special value `0` for _all_ legacy modules and special values for `DQMGlobalEDAnalyzer`s, where the local MEs need to match the life cycle of the `runCache` (module id + run number), and `DQMEDAnalyzer`s, where the `streamID` is combined with the `moduleID` to get a unique identifier for each stream instance.
- The live cycle of _global_ MEs is driven by the `initLumi/cleanupLumi` hooks called via the edm service interface. They are kept in a set of containers indexed by run and lumi number. For `RUN` MEs, the lumi number is 0; for `JOB` MEs, run and lumi are zero. The special pair `(0,0)` is also used for _prototypes_: Global MEs that are not currently associated to any run or lumi, but can (and _have to_, for the legacy guarantees) be recycled once a run or lumi starts.
- If there are no concurrent lumisections, both _local_ and _global_ MEs live for the entire job and are always connected in the same way, which means all legacy interactions continue to work. `assertLegacySafe` (enabled by default) checks for this condition and crashes the job if it is violated.

Expand Down
25 changes: 18 additions & 7 deletions DQMServices/Demo/test/TestDQMEDAnalyzer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -332,15 +332,17 @@ class TestDQMGlobalRunSummaryEDAnalyzer : public DQMGlobalRunSummaryEDAnalyzer<T
};
DEFINE_FWK_MODULE(TestDQMGlobalRunSummaryEDAnalyzer);

#include "FWCore/Framework/interface/EDAnalyzer.h"
class TestLegacyEDAnalyzer : public edm::EDAnalyzer {
#include "FWCore/Framework/interface/one/EDAnalyzer.h"
class TestLegacyEDAnalyzer : public edm::one::EDAnalyzer<edm::one::SharedResources, edm::one::WatchRuns> {
public:
typedef dqm::legacy::DQMStore DQMStore;
typedef dqm::legacy::MonitorElement MonitorElement;

explicit TestLegacyEDAnalyzer(const edm::ParameterSet& iConfig)
: mymes_(iConfig.getParameter<std::string>("folder"), iConfig.getParameter<int>("howmany")),
myvalue_(iConfig.getParameter<double>("value")) {}
myvalue_(iConfig.getParameter<double>("value")) {
usesResource("DQMStore");
}

~TestLegacyEDAnalyzer() override{};

Expand All @@ -357,6 +359,7 @@ class TestLegacyEDAnalyzer : public edm::EDAnalyzer {
edm::Service<DQMStore> store;
mymes_.bookall(*store);
}
void endRun(edm::Run const&, edm::EventSetup const&) override {}

void analyze(const edm::Event& iEvent, const edm::EventSetup& iSetup) override {
mymes_.fillall(iEvent.luminosityBlock(), iEvent.run(), myvalue_);
Expand All @@ -367,14 +370,16 @@ class TestLegacyEDAnalyzer : public edm::EDAnalyzer {
};
DEFINE_FWK_MODULE(TestLegacyEDAnalyzer);

class TestLegacyFillRunEDAnalyzer : public edm::EDAnalyzer {
class TestLegacyFillRunEDAnalyzer : public edm::one::EDAnalyzer<edm::one::SharedResources, edm::one::WatchRuns> {
public:
typedef dqm::legacy::DQMStore DQMStore;
typedef dqm::legacy::MonitorElement MonitorElement;

explicit TestLegacyFillRunEDAnalyzer(const edm::ParameterSet& iConfig)
: mymes_(iConfig.getParameter<std::string>("folder"), iConfig.getParameter<int>("howmany")),
myvalue_(iConfig.getParameter<double>("value")) {}
myvalue_(iConfig.getParameter<double>("value")) {
usesResource("DQMStore");
}

~TestLegacyFillRunEDAnalyzer() override{};

Expand All @@ -392,6 +397,7 @@ class TestLegacyFillRunEDAnalyzer : public edm::EDAnalyzer {
mymes_.bookall(*store);
mymes_.fillall(0, run.run(), myvalue_);
}
void endRun(edm::Run const&, edm::EventSetup const&) override {}

void analyze(const edm::Event& iEvent, const edm::EventSetup& iSetup) override {}

Expand All @@ -400,14 +406,17 @@ class TestLegacyFillRunEDAnalyzer : public edm::EDAnalyzer {
};
DEFINE_FWK_MODULE(TestLegacyFillRunEDAnalyzer);

class TestLegacyFillLumiEDAnalyzer : public edm::EDAnalyzer {
class TestLegacyFillLumiEDAnalyzer
: public edm::one::EDAnalyzer<edm::one::SharedResources, edm::one::WatchRuns, edm::one::WatchLuminosityBlocks> {
public:
typedef dqm::legacy::DQMStore DQMStore;
typedef dqm::legacy::MonitorElement MonitorElement;

explicit TestLegacyFillLumiEDAnalyzer(const edm::ParameterSet& iConfig)
: mymes_(iConfig.getParameter<std::string>("folder"), iConfig.getParameter<int>("howmany")),
myvalue_(iConfig.getParameter<double>("value")) {}
myvalue_(iConfig.getParameter<double>("value")) {
usesResource("DQMStore");
}

~TestLegacyFillLumiEDAnalyzer() override{};

Expand All @@ -424,10 +433,12 @@ class TestLegacyFillLumiEDAnalyzer : public edm::EDAnalyzer {
edm::Service<DQMStore> store;
mymes_.bookall(*store);
}
void endRun(edm::Run const&, edm::EventSetup const&) override {}

void beginLuminosityBlock(edm::LuminosityBlock const& lumi, edm::EventSetup const&) override {
mymes_.fillall(lumi.luminosityBlock(), lumi.run(), myvalue_);
}
void endLuminosityBlock(edm::LuminosityBlock const& lumi, edm::EventSetup const&) override {}

void analyze(const edm::Event& iEvent, const edm::EventSetup& iSetup) override {}

Expand Down
10 changes: 7 additions & 3 deletions DQMServices/Demo/test/TestHarvester.cc
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,9 @@ class TestHarvester : public DQMEDHarvester {

DEFINE_FWK_MODULE(TestHarvester);

#include "FWCore/Framework/interface/EDAnalyzer.h"
class TestLegacyHarvester : public edm::EDAnalyzer {
#include "FWCore/Framework/interface/one/EDAnalyzer.h"
class TestLegacyHarvester
: public edm::one::EDAnalyzer<edm::one::SharedResources, edm::one::WatchRuns, edm::one::WatchLuminosityBlocks> {
private:
std::string folder_;
std::string whathappened;
Expand All @@ -59,7 +60,9 @@ class TestLegacyHarvester : public edm::EDAnalyzer {
typedef dqm::legacy::MonitorElement MonitorElement;

explicit TestLegacyHarvester(const edm::ParameterSet &iConfig)
: folder_(iConfig.getParameter<std::string>("folder")) {}
: folder_(iConfig.getParameter<std::string>("folder")) {
usesResource("DQMStore");
}
~TestLegacyHarvester() override {}

void beginRun(const edm::Run &run, const edm::EventSetup &iSetup) override {
Expand All @@ -73,6 +76,7 @@ class TestLegacyHarvester : public edm::EDAnalyzer {
out->Fill(whathappened);
}

void beginLuminosityBlock(edm::LuminosityBlock const &lumi, edm::EventSetup const &) override {}
void endLuminosityBlock(edm::LuminosityBlock const &lumi, edm::EventSetup const &) override {
whathappened += "endLumi(" + std::to_string(lumi.run()) + "," + std::to_string(lumi.luminosityBlock()) + ") ";
}
Expand Down