Skip to content

Commit 8ed3144

Browse files
committed
Implement edmtest::GenericCloner (alt version)
1 parent eb697b7 commit 8ed3144

File tree

3 files changed

+277
-0
lines changed

3 files changed

+277
-0
lines changed
Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
/*
2+
* This EDProducer will clone all the event products declared by its configuration, using their ROOT dictionaries.
3+
*
4+
* The products can be specified either as module labels (e.g. "<module label>") or as branch names (e.g.
5+
* "<product type>_<module label>_<instance name>_<process name>").
6+
*
7+
* If a module label is used, no underscore ("_") must be present; this module will clone all the products produced by
8+
* that module, including those produced by the Transformer functionality (such as the implicitly copied-to-host
9+
* products in case of Alpaka-based modules).
10+
* If a branch name is used, all four fields must be present, separated by underscores; this module will clone only on
11+
* the matching product(s).
12+
*
13+
* Glob expressions ("?" and "*") are supported in module labels and within the individual fields of branch names,
14+
* similar to an OutputModule's "keep" statements.
15+
* Use "*" to clone all products.
16+
*
17+
* For example, in the case of Alpaka-based modules running on a device, using
18+
*
19+
* eventProducts = cms.untracked.vstring( "module" )
20+
*
21+
* will cause "module" to run, along with automatic copy of its device products to the host, and will attempt to clone
22+
* all device and host products.
23+
* To clone only the host product, the branch can be specified explicitly with
24+
*
25+
* eventProducts = cms.untracked.vstring( "HostProductType_module_*_*" )
26+
*
27+
* .
28+
*/
29+
30+
#include <cstring>
31+
#include <iostream>
32+
#include <memory>
33+
#include <string>
34+
#include <string_view>
35+
#include <utility>
36+
#include <vector>
37+
38+
#include <TBufferFile.h>
39+
40+
#include "DataFormats/Provenance/interface/ProductDescription.h"
41+
#include "DataFormats/Provenance/interface/ProductNamePattern.h"
42+
#include "FWCore/Framework/interface/Event.h"
43+
#include "FWCore/Framework/interface/WrapperBaseHandle.h"
44+
#include "FWCore/Framework/interface/WrapperBaseOrphanHandle.h"
45+
#include "FWCore/Framework/interface/global/EDProducer.h"
46+
#include "FWCore/MessageLogger/interface/MessageLogger.h"
47+
#include "FWCore/ParameterSet/interface/ConfigurationDescriptions.h"
48+
#include "FWCore/ParameterSet/interface/ParameterDescriptionNode.h"
49+
#include "FWCore/ParameterSet/interface/ParameterSet.h"
50+
#include "FWCore/ParameterSet/interface/ParameterSetDescription.h"
51+
#include "FWCore/Reflection/interface/ObjectWithDict.h"
52+
#include "FWCore/Utilities/interface/EDMException.h"
53+
54+
namespace edmtest {
55+
56+
class GenericClonerAlt : public edm::global::EDProducer<> {
57+
public:
58+
explicit GenericClonerAlt(edm::ParameterSet const&);
59+
~GenericClonerAlt() override = default;
60+
61+
void produce(edm::StreamID, edm::Event&, edm::EventSetup const&) const override;
62+
63+
static void fillDescriptions(edm::ConfigurationDescriptions& descriptions);
64+
65+
private:
66+
struct Entry {
67+
edm::TypeWithDict objectType_;
68+
edm::TypeWithDict wrappedType_;
69+
edm::EDGetToken getToken_;
70+
edm::EDPutToken putToken_;
71+
};
72+
73+
std::vector<edm::ProductNamePattern> eventPatterns_;
74+
std::vector<Entry> eventProducts_;
75+
std::string label_;
76+
bool verbose_;
77+
};
78+
79+
GenericClonerAlt::GenericClonerAlt(edm::ParameterSet const& config)
80+
: eventPatterns_(edm::productPatterns(config.getParameter<std::vector<std::string>>("eventProducts"))),
81+
label_(config.getParameter<std::string>("@module_label")),
82+
verbose_(config.getUntrackedParameter<bool>("verbose")) {
83+
eventProducts_.reserve(eventPatterns_.size());
84+
85+
callWhenNewProductsRegistered([this](edm::ProductDescription const& product) {
86+
static const std::string_view kPathStatus("edm::PathStatus");
87+
static const std::string_view kEndPathStatus("edm::EndPathStatus");
88+
89+
switch (product.branchType()) {
90+
case edm::InEvent:
91+
if (product.className() == kPathStatus or product.className() == kEndPathStatus) {
92+
return;
93+
}
94+
for (auto& pattern : eventPatterns_) {
95+
if (pattern.match(product)) {
96+
// check that the product is not transient
97+
if (product.transient()) {
98+
edm::LogWarning("GenericCloner") << "Event product " << product.branchName() << " of type "
99+
<< product.unwrappedType() << " is transient, will not be cloned.";
100+
break;
101+
}
102+
if (verbose_) {
103+
edm::LogInfo("GenericCloner")
104+
<< "will clone Event product " << product.branchName() << " of type " << product.unwrappedType();
105+
}
106+
Entry entry;
107+
entry.objectType_ = product.unwrappedType();
108+
entry.wrappedType_ = product.wrappedType();
109+
// TODO move this to EDConsumerBase::consumes() ?
110+
entry.getToken_ = this->consumes(
111+
edm::TypeToGet{product.unwrappedTypeID(), edm::PRODUCT_TYPE},
112+
edm::InputTag{product.moduleLabel(), product.productInstanceName(), product.processName()});
113+
entry.putToken_ = this->produces(product.unwrappedTypeID(), product.productInstanceName());
114+
eventProducts_.emplace_back(std::move(entry));
115+
break;
116+
}
117+
}
118+
break;
119+
120+
case edm::InLumi:
121+
case edm::InRun:
122+
case edm::InProcess:
123+
// lumi, run and process products are not supported
124+
break;
125+
126+
default:
127+
throw edm::Exception(edm::errors::LogicError)
128+
<< "Unexpected product type " << product.branchType() << "\nPlease contact a Framework developer.";
129+
}
130+
});
131+
}
132+
133+
void GenericClonerAlt::produce(edm::StreamID /*unused*/, edm::Event& event, edm::EventSetup const& /*unused*/) const {
134+
for (auto& product : eventProducts_) {
135+
edm::Handle<edm::WrapperBase> handle(product.objectType_.typeInfo());
136+
event.getByToken(product.getToken_, handle);
137+
edm::WrapperBase const* wrapper = handle.product();
138+
139+
// write the wrapper into a TBuffer
140+
TBufferFile buffer(TBuffer::kWrite);
141+
product.wrappedType_.getClass()->Streamer(const_cast<edm::WrapperBase*>(wrapper), buffer);
142+
143+
// read back a copy of the product form the TBuffer
144+
buffer.SetReadMode();
145+
buffer.SetBufferOffset(0);
146+
std::unique_ptr<edm::WrapperBase> clone(
147+
reinterpret_cast<edm::WrapperBase*>(product.wrappedType_.getClass()->New()));
148+
product.wrappedType_.getClass()->Streamer(clone.get(), buffer);
149+
150+
// move the wrapper into the Event
151+
event.put(product.putToken_, std::move(clone));
152+
}
153+
}
154+
155+
void GenericClonerAlt::fillDescriptions(edm::ConfigurationDescriptions& descriptions) {
156+
descriptions.setComment(
157+
R"(This EDProducer will clone all the event products declared by its configuration, using their ROOT dictionaries.
158+
159+
The products can be specified either as module labels (e.g. "<module label>") or as branch names (e.g. "<product type>_<module label>_<instance name>_<process name>").
160+
If a module label is used, no underscore ("_") must be present; this module will clone all the products produced by that module, including those produced by the Transformer functionality (such as the implicitly copied-to-host products in case of Alpaka-based modules).
161+
If a branch name is used, all four fields must be present, separated by underscores; this module will clone only on the matching product(s).
162+
163+
Glob expressions ("?" and "*") are supported in module labels and within the individual fields of branch names, similar to an OutputModule's "keep" statements.
164+
Use "*" to clone all products.
165+
166+
For example, in the case of Alpaka-based modules running on a device, using
167+
168+
eventProducts = cms.untracked.vstring( "module" )
169+
170+
will cause "module" to run, along with automatic copy of its device products to the host, and will attempt to clone all device and host products.
171+
To clone only the host product, the branch can be specified explicitly with
172+
173+
eventProducts = cms.untracked.vstring( "HostProductType_module_*_*" )
174+
175+
.)");
176+
177+
edm::ParameterSetDescription desc;
178+
desc.add<std::vector<std::string>>("eventProducts", {})
179+
->setComment("List of modules or branches whose event products will be cloned.");
180+
desc.addUntracked<bool>("verbose", false)
181+
->setComment("Print the branch names of the products that will be cloned.");
182+
descriptions.addWithDefaultLabel(desc);
183+
}
184+
185+
} // namespace edmtest
186+
187+
#include "FWCore/Framework/interface/MakerMacros.h"
188+
DEFINE_FWK_MODULE(edmtest::GenericClonerAlt);

FWCore/TestModules/test/BuildFile.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
<test name="TestFWCoreModulesEventIDValidator" command="cmsRun ${LOCALTOP}/src/FWCore/TestModules/test/testEventIDValidator_cfg.py"/>
22

33
<test name="TestFWCoreModulesGenericCloner" command="cmsRun ${LOCALTOP}/src/FWCore/TestModules/test/testGenericCloner_cfg.py"/>
4+
5+
<test name="TestFWCoreModulesGenericClonerAlt" command="cmsRun ${LOCALTOP}/src/FWCore/TestModules/test/testGenericClonerAlt_cfg.py"/>
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
import FWCore.ParameterSet.Config as cms
2+
3+
process = cms.Process("TEST")
4+
5+
process.load("FWCore.MessageService.MessageLogger_cfi")
6+
process.MessageLogger.cerr.INFO.limit = 10000000
7+
8+
process.options.numberOfThreads = 1
9+
process.options.numberOfStreams = 1
10+
11+
process.source = cms.Source("EmptySource")
12+
process.maxEvents.input = 10
13+
14+
# produce, clone and validate products of type int
15+
process.produceInt = cms.EDProducer("edmtest::GlobalIntProducer",
16+
value = cms.int32(42)
17+
)
18+
19+
process.cloneInt = cms.EDProducer("edmtest::GenericClonerAlt",
20+
eventProducts = cms.vstring("produceInt"),
21+
verbose = cms.untracked.bool(True)
22+
)
23+
24+
process.validateInt = cms.EDAnalyzer("edmtest::GlobalIntAnalyzer",
25+
source = cms.InputTag("cloneInt"),
26+
expected = cms.int32(42)
27+
)
28+
29+
process.taskInt = cms.Task(process.produceInt, process.cloneInt)
30+
31+
process.pathInt = cms.Path(process.validateInt, process.taskInt)
32+
33+
# produce, clone and validate products of type std::string
34+
process.produceString = cms.EDProducer("edmtest::GlobalStringProducer",
35+
value = cms.string("Hello world")
36+
)
37+
38+
process.cloneString = cms.EDProducer("edmtest::GenericClonerAlt",
39+
eventProducts = cms.vstring("produceString"),
40+
verbose = cms.untracked.bool(True)
41+
)
42+
43+
process.validateString = cms.EDAnalyzer("edmtest::GlobalStringAnalyzer",
44+
source = cms.InputTag("cloneString"),
45+
expected = cms.string("Hello world")
46+
)
47+
48+
process.taskString = cms.Task(process.produceString, process.cloneString)
49+
50+
process.pathString = cms.Path(process.validateString, process.taskString)
51+
52+
# produce, clone and validate products of type edm::EventID
53+
process.eventIds = cms.EDProducer("edmtest::EventIDProducer")
54+
55+
process.cloneIdsByLabel = cms.EDProducer("edmtest::GenericClonerAlt",
56+
eventProducts = cms.vstring("eventIds"),
57+
verbose = cms.untracked.bool(True)
58+
)
59+
60+
process.cloneIdsByBranch = cms.EDProducer("edmtest::GenericClonerAlt",
61+
eventProducts = cms.vstring("*_eventIds__TEST"),
62+
verbose = cms.untracked.bool(True)
63+
)
64+
65+
process.validateIdsByLabel = cms.EDAnalyzer("edmtest::EventIDValidator",
66+
source = cms.untracked.InputTag('cloneIdsByLabel')
67+
)
68+
69+
process.validateIdsByBranch = cms.EDAnalyzer("edmtest::EventIDValidator",
70+
source = cms.untracked.InputTag('cloneIdsByBranch')
71+
)
72+
73+
process.taskIds = cms.Task(process.eventIds, process.cloneIdsByLabel, process.cloneIdsByBranch)
74+
75+
process.pathIds = cms.Path(process.validateIdsByLabel + process.validateIdsByBranch, process.taskIds)
76+
77+
# will not clone a transient product
78+
process.produceTransient = cms.EDProducer("TransientIntProducer",
79+
ivalue = cms.int32(22)
80+
)
81+
82+
process.cloneTransient = cms.EDProducer("edmtest::GenericClonerAlt",
83+
eventProducts = cms.vstring("produceTransient"),
84+
verbose = cms.untracked.bool(True)
85+
)
86+
87+
process.pathTransient = cms.Path(process.produceTransient + process.cloneTransient)

0 commit comments

Comments
 (0)