diff --git a/FWCore/Modules/src/EmptySourceFromEventIDs.cc b/FWCore/Modules/src/EmptySourceFromEventIDs.cc new file mode 100644 index 0000000000000..31dd2b02c7de3 --- /dev/null +++ b/FWCore/Modules/src/EmptySourceFromEventIDs.cc @@ -0,0 +1,64 @@ +#include "FWCore/Framework/interface/Event.h" +#include "FWCore/Framework/interface/InputSource.h" +#include "FWCore/ParameterSet/interface/ConfigurationDescriptions.h" +#include "FWCore/ParameterSet/interface/ParameterSetDescription.h" +#include "FWCore/Sources/interface/IDGeneratorSourceBase.h" + +/* + * IDGeneratorSourceBase implements the logic to generate run, lumi, and event numbers, and event timestamps. + * These will actually be overwritten by this source, but it's easier to do that than to write a new source base + * type from scratch. + */ + +class EmptySourceFromEventIDs : public edm::IDGeneratorSourceBase { +public: + explicit EmptySourceFromEventIDs(edm::ParameterSet const&, edm::InputSourceDescription const&); + ~EmptySourceFromEventIDs() override = default; + + static void fillDescriptions(edm::ConfigurationDescriptions& descriptions); + +private: + bool setRunAndEventInfo(edm::EventID& id, edm::TimeValue_t& time, edm::EventAuxiliary::ExperimentType& type) override; + void readEvent_(edm::EventPrincipal& e) override; + + std::vector events_; +}; + +// Note that almost all configuration parameters passed to IDGeneratorSourceBase will effectively be ignored, because +// the EmptySourceFromEventIDs will explicitly set the run, lumi, and event numbers, the timestamp, and the event type. +EmptySourceFromEventIDs::EmptySourceFromEventIDs(edm::ParameterSet const& config, + edm::InputSourceDescription const& desc) + : IDGeneratorSourceBase(config, desc, false), + events_{config.getUntrackedParameter>("events")} // List of event ids to create +{ + // Invert the order of the events so they can efficiently be popped off the back of the vector + std::reverse(events_.begin(), events_.end()); +} + +bool EmptySourceFromEventIDs::setRunAndEventInfo(edm::EventID& event, + edm::TimeValue_t& time, + edm::EventAuxiliary::ExperimentType& type) { + if (events_.empty()) { + return false; + } + + event = std::move(events_.back()); + events_.pop_back(); + return true; +} + +void EmptySourceFromEventIDs::readEvent_(edm::EventPrincipal& e) { + doReadEvent(e, [](auto const&) {}); +} + +void EmptySourceFromEventIDs::fillDescriptions(edm::ConfigurationDescriptions& descriptions) { + edm::ParameterSetDescription desc; + desc.setComment("Creates runs, lumis and events (containing no products) based on the provided list of event ids."); + edm::IDGeneratorSourceBase::fillDescription(desc); + + desc.addUntracked>("events", {}); + descriptions.add("source", desc); +} + +#include "FWCore/Framework/interface/InputSourceMacros.h" +DEFINE_FWK_INPUT_SOURCE(EmptySourceFromEventIDs); diff --git a/FWCore/Modules/test/BuildFile.xml b/FWCore/Modules/test/BuildFile.xml index d1054436b83b1..f33267058f2d0 100644 --- a/FWCore/Modules/test/BuildFile.xml +++ b/FWCore/Modules/test/BuildFile.xml @@ -4,6 +4,8 @@ + + diff --git a/FWCore/Modules/test/testEmptySourceFromEventIDs_cfg.py b/FWCore/Modules/test/testEmptySourceFromEventIDs_cfg.py new file mode 100644 index 0000000000000..889418641a3a3 --- /dev/null +++ b/FWCore/Modules/test/testEmptySourceFromEventIDs_cfg.py @@ -0,0 +1,49 @@ +#! /usr/bin/env cmsRun + +import FWCore.ParameterSet.Config as cms + +events = cms.VEventID( + # Run 100 + cms.EventID(100, 1, 1), + cms.EventID(100, 1, 2), + cms.EventID(100, 2, 3), + cms.EventID(100, 2, 4), + cms.EventID(100, 3, 5), + # Run 101 + cms.EventID(101, 1, 1), + cms.EventID(101, 1, 2), + cms.EventID(101, 2, 3), + cms.EventID(101, 2, 4), + cms.EventID(101, 3, 5), + # Run 102 + cms.EventID(102, 1, 1), + cms.EventID(102, 1, 2), + cms.EventID(102, 2, 3), + cms.EventID(102, 2, 4), + cms.EventID(102, 3, 5), + # Run 103 + cms.EventID(103, 1, 1), + cms.EventID(103, 1, 2), + cms.EventID(103, 2, 3), + cms.EventID(103, 2, 4), + cms.EventID(103, 3, 5), +) + +process = cms.Process("TEST") + +process.source = cms.Source("EmptySourceFromEventIDs", + events = cms.untracked(events) +) + +process.maxEvents = cms.untracked.PSet( + input = cms.untracked.int32(42) +) + +# EventIDChecker requires synchronizing on LuminosityBlock boundaries +process.options.numberOfThreads = 4 +process.options.numberOfStreams = 4 +process.options.numberOfConcurrentLuminosityBlocks = 1 + +process.check = cms.EDAnalyzer("EventIDChecker", eventSequence = cms.untracked(events)) + +process.endp = cms.EndPath(process.check) diff --git a/FWCore/TestModules/README.md b/FWCore/TestModules/README.md index b8875b9d6b401..bd4cadf13823d 100644 --- a/FWCore/TestModules/README.md +++ b/FWCore/TestModules/README.md @@ -4,6 +4,23 @@ This package contains modules that are used in framework tests, but are generic-enough to be usable outside of the framework as well. Their interfaces are intended to be relatively stable. + ## `edmtest::StreamIDFilter` This module can be used to reject all events in specific streams. + + +## `edmtest::EventIDProducer` + +This module reads the `EventID` from the current event and copies it as a data +product into the `Event`. + + +## `edmtest::EventIDValidator` + +This module reads the `EventID` from the current event and compares it to a data +product read from the `Event`. + +Together `edmtest::EventIDProducer` and `edmtest::EventIDValidator` can be used +to validate that an object produced in a given event is being read back in the +same event. diff --git a/FWCore/TestModules/plugins/BuildFile.xml b/FWCore/TestModules/plugins/BuildFile.xml index d59f00b4a326d..a7126fae22e96 100644 --- a/FWCore/TestModules/plugins/BuildFile.xml +++ b/FWCore/TestModules/plugins/BuildFile.xml @@ -1,5 +1,8 @@ + + + diff --git a/FWCore/TestModules/plugins/EventIDProducer.cc b/FWCore/TestModules/plugins/EventIDProducer.cc new file mode 100644 index 0000000000000..f867b3e578cff --- /dev/null +++ b/FWCore/TestModules/plugins/EventIDProducer.cc @@ -0,0 +1,31 @@ +// CMSSW include files +#include "DataFormats/Provenance/interface/EventID.h" +#include "FWCore/Framework/interface/Event.h" +#include "FWCore/Framework/interface/global/EDProducer.h" +#include "FWCore/ParameterSet/interface/ConfigurationDescriptions.h" +#include "FWCore/ParameterSet/interface/ParameterSetDescription.h" +#include "FWCore/Utilities/interface/EDPutToken.h" + +namespace edmtest { + + class EventIDProducer : public edm::global::EDProducer<> { + public: + EventIDProducer(edm::ParameterSet const& config) : token_(produces()) {} + + void produce(edm::StreamID, edm::Event& event, edm::EventSetup const&) const final { + event.emplace(token_, event.id()); + } + + static void fillDescriptions(edm::ConfigurationDescriptions& descriptions) { + edm::ParameterSetDescription desc; + descriptions.addWithDefaultLabel(desc); + } + + private: + edm::EDPutTokenT token_; + }; + +} // namespace edmtest + +#include "FWCore/Framework/interface/MakerMacros.h" +DEFINE_FWK_MODULE(edmtest::EventIDProducer); diff --git a/FWCore/TestModules/plugins/EventIDValidator.cc b/FWCore/TestModules/plugins/EventIDValidator.cc new file mode 100644 index 0000000000000..99be1f6e28426 --- /dev/null +++ b/FWCore/TestModules/plugins/EventIDValidator.cc @@ -0,0 +1,40 @@ +// CMSSW include files +#include "DataFormats/Provenance/interface/EventID.h" +#include "FWCore/Framework/interface/Event.h" +#include "FWCore/Framework/interface/global/EDAnalyzer.h" +#include "FWCore/ParameterSet/interface/ConfigurationDescriptions.h" +#include "FWCore/ParameterSet/interface/ParameterSetDescription.h" +#include "FWCore/Utilities/interface/EDGetToken.h" +#include "FWCore/Utilities/interface/Exception.h" + +namespace edmtest { + + class EventIDValidator : public edm::global::EDAnalyzer<> { + public: + EventIDValidator(edm::ParameterSet const& config) + : token_(consumes(config.getUntrackedParameter("source"))) {} + + void analyze(edm::StreamID, edm::Event const& event, edm::EventSetup const&) const final { + auto const& id = event.get(token_); + if (id != event.id()) { + throw cms::Exception("InvalidValue") << "EventIDValidator: found invalid input value\n" + << id << "\nwhile expecting\n" + << event.id(); + } + } + + static void fillDescriptions(edm::ConfigurationDescriptions& descriptions) { + edm::ParameterSetDescription desc; + desc.addUntracked("source", edm::InputTag{"eventIDProducer", ""}) + ->setComment("EventID product to read from the event"); + descriptions.addWithDefaultLabel(desc); + } + + private: + edm::EDGetTokenT token_; + }; + +} // namespace edmtest + +#include "FWCore/Framework/interface/MakerMacros.h" +DEFINE_FWK_MODULE(edmtest::EventIDValidator); diff --git a/FWCore/TestModules/test/BuildFile.xml b/FWCore/TestModules/test/BuildFile.xml new file mode 100644 index 0000000000000..386d18c359309 --- /dev/null +++ b/FWCore/TestModules/test/BuildFile.xml @@ -0,0 +1 @@ + diff --git a/FWCore/TestModules/test/testEventIDValidator_cfg.py b/FWCore/TestModules/test/testEventIDValidator_cfg.py new file mode 100644 index 0000000000000..76d896091c2a8 --- /dev/null +++ b/FWCore/TestModules/test/testEventIDValidator_cfg.py @@ -0,0 +1,17 @@ +import FWCore.ParameterSet.Config as cms + +process = cms.Process("TEST") + +process.options.numberOfThreads = 4 +process.options.numberOfStreams = 4 + +process.source = cms.Source("EmptySource") +process.maxEvents.input = 10 + +process.eventIds = cms.EDProducer("edmtest::EventIDProducer") + +process.eventValidator = cms.EDAnalyzer("edmtest::EventIDValidator", + source = cms.untracked.InputTag('eventIds') +) + +process.path = cms.Path(process.eventIds + process.eventValidator)