Skip to content

Commit 22ba0a9

Browse files
committed
Implement the CheckClassInfo module
Add an automated test that checks the ClassInfo of all persistent HLT products.
1 parent f99f84f commit 22ba0a9

File tree

4 files changed

+192
-0
lines changed

4 files changed

+192
-0
lines changed

FWCore/TestModules/README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,9 @@ product read from the `Event`.
3737
Together `edmtest::EventIDProducer` and `edmtest::EventIDValidator` can be used
3838
to validate that an object produced in a given event is being read back in the
3939
same event.
40+
41+
42+
## `edmtest::CheckClassInfo`
43+
44+
This module will query the TClass, ClassProperty and ClassInfo of all the
45+
persistent products specified in its configuration.
Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
/*
2+
* This EDAnalyzer will query the TClass, ClassProperty and ClassInfo of all the persistent products specified in its
3+
* configuration.
4+
*
5+
* The products can be specified either as module labels (e.g. "<module label>") or as full product names (e.g.
6+
* "<product type>_<module label>_<instance name>_<process name>").
7+
* If a module label is used, no underscore ("_") must be present; this module will check the types of all the
8+
* collections produced by that module, including those produced by the Transformer functionality (such as the
9+
* implicitly copied-to-host products in case of Alpaka-based modules).
10+
* If a full product name is used, all four fields must be present, separated by underscores; this module will depend
11+
* only on 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 check all products of a given category.
16+
*/
17+
18+
#include <algorithm>
19+
#include <string>
20+
#include <regex>
21+
#include <vector>
22+
23+
#include "DataFormats/Provenance/interface/ProductDescription.h"
24+
#include "DataFormats/Provenance/interface/ProductNamePattern.h"
25+
#include "FWCore/Framework/interface/global/EDAnalyzer.h"
26+
#include "FWCore/MessageLogger/interface/MessageLogger.h"
27+
#include "FWCore/ParameterSet/interface/ConfigurationDescriptions.h"
28+
#include "FWCore/ParameterSet/interface/ParameterDescriptionNode.h"
29+
#include "FWCore/ParameterSet/interface/ParameterSet.h"
30+
#include "FWCore/ParameterSet/interface/ParameterSetDescription.h"
31+
#include "FWCore/Utilities/interface/EDMException.h"
32+
33+
namespace edmtest {
34+
35+
class CheckClassInfo : public edm::global::EDAnalyzer<> {
36+
public:
37+
explicit CheckClassInfo(edm::ParameterSet const&);
38+
~CheckClassInfo() override = default;
39+
40+
void analyze(edm::StreamID, edm::Event const&, edm::EventSetup const&) const override {}
41+
42+
static void fillDescriptions(edm::ConfigurationDescriptions& descriptions);
43+
44+
private:
45+
void check(edm::ProductDescription const& product) const;
46+
47+
std::vector<edm::ProductNamePattern> eventProducts_;
48+
std::vector<edm::ProductNamePattern> lumiProducts_;
49+
std::vector<edm::ProductNamePattern> runProducts_;
50+
std::vector<edm::ProductNamePattern> processProducts_;
51+
};
52+
53+
CheckClassInfo::CheckClassInfo(edm::ParameterSet const& config)
54+
: eventProducts_(edm::productPatterns(config.getUntrackedParameter<std::vector<std::string>>("eventProducts"))),
55+
lumiProducts_(edm::productPatterns(config.getUntrackedParameter<std::vector<std::string>>("lumiProducts"))),
56+
runProducts_(edm::productPatterns(config.getUntrackedParameter<std::vector<std::string>>("runProducts"))),
57+
processProducts_(
58+
edm::productPatterns(config.getUntrackedParameter<std::vector<std::string>>("processProducts"))) {
59+
callWhenNewProductsRegistered([this](edm::ProductDescription const& product) {
60+
switch (product.branchType()) {
61+
case edm::InEvent:
62+
for (auto const& label : eventProducts_)
63+
if (label.match(product)) {
64+
check(product);
65+
break;
66+
}
67+
break;
68+
69+
case edm::InLumi:
70+
for (auto const& label : lumiProducts_)
71+
if (label.match(product)) {
72+
check(product);
73+
break;
74+
}
75+
break;
76+
77+
case edm::InRun:
78+
for (auto const& label : runProducts_)
79+
if (label.match(product)) {
80+
check(product);
81+
break;
82+
}
83+
break;
84+
85+
case edm::InProcess:
86+
for (auto const& label : processProducts_)
87+
if (label.match(product)) {
88+
check(product);
89+
break;
90+
}
91+
break;
92+
93+
default:
94+
throw edm::Exception(edm::errors::LogicError)
95+
<< "Unexpected branch type " << product.branchType() << "\nPlease contact a Framework developer\n";
96+
}
97+
});
98+
}
99+
100+
void CheckClassInfo::check(edm::ProductDescription const& product) const {
101+
if (product.transient()) {
102+
edm::LogVerbatim("CheckClassInfo") << "The product " << product.friendlyClassName() << '_'
103+
<< product.moduleLabel() << '_' << product.productInstanceName() << '_'
104+
<< product.processName() << " is transient, and will not be queried.\n";
105+
} else {
106+
edm::LogVerbatim log("CheckClassInfo");
107+
log << "product " << product.friendlyClassName() << '_' << product.moduleLabel() << '_'
108+
<< product.productInstanceName() << '_' << product.processName() << " :\n";
109+
log << " wrapper type " << product.wrappedType().name() << '\n';
110+
TClass* type = product.wrappedType().getClass();
111+
log << " TClass pointer " << type << '\n';
112+
if (type == nullptr) {
113+
throw edm::Exception(edm::errors::DictionaryNotFound)
114+
<< "Failed to get a valid TClass pointer for the persistent type " << product.wrappedType().name();
115+
}
116+
auto prop = type->ClassProperty();
117+
log << " TClass property " << prop << '\n';
118+
ClassInfo_t* info = type->GetClassInfo();
119+
log << " ClassInfo pointer" << info << '\n';
120+
if (info == nullptr) {
121+
throw edm::Exception(edm::errors::DictionaryNotFound)
122+
<< "Failed to get a valid ClassInfo_t pointer for the persistent type " << product.wrappedType().name();
123+
}
124+
}
125+
}
126+
127+
void CheckClassInfo::fillDescriptions(edm::ConfigurationDescriptions& descriptions) {
128+
descriptions.setComment(
129+
R"(This EDAnalyzer will query the TClass, ClassProperty and ClassInfo of all the persistent products specified in its
130+
configuration.
131+
132+
The products can be specified either as module labels (e.g. "<module label>") or as full product names (e.g.
133+
"<product type>_<module label>_<instance name>_<process name>").
134+
If a module label is used, no underscore ("_") must be present; this module will check the types of all the collections
135+
produced by that module, including those produced by the Transformer functionality (such as the implicitly copied-to-host
136+
products in case of Alpaka-based modules).
137+
If a full product name is used, all four fields must be present, separated by underscores; this module will depend only
138+
on the matching product(s).
139+
140+
Glob expressions ("?" and "*") are supported in module labels and within the individual fields of branch names, similar
141+
to an OutputModule's "keep" statements. Use "*" to check all products of a given category.)");
142+
143+
edm::ParameterSetDescription desc;
144+
desc.addUntracked<std::vector<std::string>>("eventProducts", {})
145+
->setComment("List of modules or product names whose event products this module will check.");
146+
desc.addUntracked<std::vector<std::string>>("lumiProducts", {})
147+
->setComment("List of modules or product names whose lumi products this module will check.");
148+
desc.addUntracked<std::vector<std::string>>("runProducts", {})
149+
->setComment("List of modules or product names whose run products this module will check.");
150+
desc.addUntracked<std::vector<std::string>>("processProducts", {})
151+
->setComment("List of modules or product names whose process products this module will check.");
152+
descriptions.addWithDefaultLabel(desc);
153+
}
154+
155+
} // namespace edmtest
156+
157+
#include "FWCore/Framework/interface/MakerMacros.h"
158+
DEFINE_FWK_MODULE(edmtest::CheckClassInfo);
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
<test name="TestFWCoreModulesEventIDValidator" command="cmsRun ${LOCALTOP}/src/FWCore/TestModules/test/testEventIDValidator_cfg.py"/>
2+
<test name="TestFWCoreModulesCheckClassInfo" command="cmsRun ${LOCALTOP}/src/FWCore/TestModules/test/testCheckClassInfo_cfg.py"/>
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import FWCore.ParameterSet.Config as cms
2+
3+
process = cms.Process("TEST")
4+
5+
# load the latest HLT configuration in order to exercise a large number of event products
6+
process.load('HLTrigger.Configuration.HLT_GRun_cff')
7+
8+
process.options.numberOfThreads = 8
9+
process.options.numberOfStreams = 8
10+
11+
# do not process any events, only construct the modules
12+
process.source = cms.Source("EmptySource")
13+
process.maxEvents.input = 0
14+
15+
# show the CheckClassInfo messages
16+
process.MessageLogger.CheckClassInfo = cms.untracked.PSet()
17+
18+
# check the ROOT dictionaries of all non-transient products declared by any module
19+
process.checkAll = cms.EDAnalyzer("edmtest::CheckClassInfo",
20+
eventProducts = cms.untracked.vstring("*")
21+
)
22+
23+
process.CheckClassInfo = cms.Path(
24+
process.checkAll
25+
)
26+
27+
process.schedule.append( process.CheckClassInfo )

0 commit comments

Comments
 (0)