From 9d851e42b83fb4fb232f2cea372d7a4f105a432b Mon Sep 17 00:00:00 2001 From: "W. David Dagenhart" Date: Tue, 25 Apr 2023 19:42:47 +0200 Subject: [PATCH] GetterOfProducts for output modules, use in DQMRootOutputModule Extends support for GetterOfProducts to output modules and uses that instead of consumesMany in DQMRootOutputModule --- .../FwkIO/plugins/DQMRootOutputModule.cc | 18 ++- FWCore/Framework/interface/GetterOfProducts.h | 76 +++++----- FWCore/Framework/interface/OutputModuleCore.h | 10 +- .../interface/global/OutputModuleBase.h | 2 - .../interface/limited/OutputModuleBase.h | 2 - .../interface/one/OutputModuleBase.h | 2 - FWCore/Framework/src/OutputModuleCore.cc | 10 ++ FWCore/Integration/plugins/BuildFile.xml | 2 +- .../plugins/TestOutputWithGetterOfProducts.cc | 141 +++++++++++++++++ .../TestOutputWithGetterOfProductsGlobal.cc | 143 ++++++++++++++++++ .../TestOutputWithGetterOfProductsLimited.cc | 143 ++++++++++++++++++ FWCore/Integration/test/run_TestGetBy.sh | 3 + ...estGetterOfProductsWithOutputModule_cfg.py | 41 +++++ 13 files changed, 543 insertions(+), 50 deletions(-) create mode 100644 FWCore/Integration/plugins/TestOutputWithGetterOfProducts.cc create mode 100644 FWCore/Integration/plugins/TestOutputWithGetterOfProductsGlobal.cc create mode 100644 FWCore/Integration/plugins/TestOutputWithGetterOfProductsLimited.cc create mode 100644 FWCore/Integration/test/testGetterOfProductsWithOutputModule_cfg.py diff --git a/DQMServices/FwkIO/plugins/DQMRootOutputModule.cc b/DQMServices/FwkIO/plugins/DQMRootOutputModule.cc index ec9a0440079f4..3e58b980e07c4 100644 --- a/DQMServices/FwkIO/plugins/DQMRootOutputModule.cc +++ b/DQMServices/FwkIO/plugins/DQMRootOutputModule.cc @@ -30,13 +30,16 @@ #include "oneapi/tbb/task_arena.h" // user include files +#include "FWCore/Framework/interface/GetterOfProducts.h" #include "FWCore/Framework/interface/one/OutputModule.h" #include "FWCore/Framework/interface/RunForOutput.h" #include "FWCore/Framework/interface/LuminosityBlockForOutput.h" +#include "FWCore/Framework/interface/TypeMatch.h" #include "DQMServices/Core/interface/DQMStore.h" #include "FWCore/ServiceRegistry/interface/Service.h" #include "FWCore/Framework/interface/MakerMacros.h" #include "FWCore/MessageLogger/interface/JobReport.h" +#include "FWCore/Utilities/interface/BranchType.h" #include "FWCore/Utilities/interface/Digest.h" #include "FWCore/Utilities/interface/GlobalIdentifier.h" @@ -235,6 +238,9 @@ class DQMRootOutputModule : public edm::one::OutputModule<> { std::vector m_seenHistories; edm::ProcessHistoryRegistry m_processHistoryRegistry; edm::JobReport::Token m_jrToken; + + edm::GetterOfProducts m_getterOfProductsLumi; + edm::GetterOfProducts m_getterOfProductsRun; }; // @@ -293,14 +299,20 @@ DQMRootOutputModule::DQMRootOutputModule(edm::ParameterSet const& pset) m_presentHistoryIndex(0), m_filterOnRun(pset.getUntrackedParameter("filterOnRun")), m_fullNameBufferPtr(&m_fullNameBuffer), - m_indicesTree(nullptr) { + m_indicesTree(nullptr), + m_getterOfProductsLumi(edm::TypeMatch(), this, edm::InLumi), + m_getterOfProductsRun(edm::TypeMatch(), this, edm::InRun) { // Declare dependencies for all Lumi and Run tokens here. In // principle could use the keep statements, but then DQMToken would // have to be made persistent (transient products are ignored), // which would lead to a need to (finally) remove underscores from // DQM module labels. - consumesMany(); - consumesMany(); + // This is needed to support unscheduled DQM modules now that + // non-consumed EDProducers are deleted from the job at beginJob. + callWhenNewProductsRegistered([this](edm::BranchDescription const& bd) { + m_getterOfProductsLumi(bd); + m_getterOfProductsRun(bd); + }); } // DQMRootOutputModule::DQMRootOutputModule(const DQMRootOutputModule& rhs) diff --git a/FWCore/Framework/interface/GetterOfProducts.h b/FWCore/Framework/interface/GetterOfProducts.h index da2406c8736a8..5c4a4e5ee5eb2 100644 --- a/FWCore/Framework/interface/GetterOfProducts.h +++ b/FWCore/Framework/interface/GetterOfProducts.h @@ -101,9 +101,13 @@ There are some variants for special cases #include "DataFormats/Common/interface/Handle.h" #include "DataFormats/Provenance/interface/BranchDescription.h" #include "FWCore/Framework/interface/Event.h" +#include "FWCore/Framework/interface/EventForOutput.h" #include "FWCore/Framework/interface/LuminosityBlock.h" +#include "FWCore/Framework/interface/LuminosityBlockForOutput.h" #include "FWCore/Framework/interface/ProcessBlock.h" +#include "FWCore/Framework/interface/ProcessBlockForOutput.h" #include "FWCore/Framework/interface/Run.h" +#include "FWCore/Framework/interface/RunForOutput.h" #include "FWCore/Framework/interface/WillGetIfMatch.h" #include "FWCore/Utilities/interface/BranchType.h" #include "FWCore/Utilities/interface/EDGetToken.h" @@ -116,6 +120,35 @@ There are some variants for special cases namespace edm { + template + struct BranchTypeForContainerType { + static const BranchType branchType = InEvent; + }; + template <> + struct BranchTypeForContainerType { + static const BranchType branchType = InLumi; + }; + template <> + struct BranchTypeForContainerType { + static const BranchType branchType = InLumi; + }; + template <> + struct BranchTypeForContainerType { + static const BranchType branchType = InRun; + }; + template <> + struct BranchTypeForContainerType { + static const BranchType branchType = InRun; + }; + template <> + struct BranchTypeForContainerType { + static const BranchType branchType = InProcess; + }; + template <> + struct BranchTypeForContainerType { + static const BranchType branchType = InProcess; + }; + template class GetterOfProducts { public: @@ -139,48 +172,13 @@ namespace edm { } } - void fillHandles(edm::Event const& event, std::vector>& handles) const { - handles.clear(); - if (branchType_ == edm::InEvent) { - handles.reserve(tokens_->size()); - for (auto const& token : *tokens_) { - if (auto handle = event.getHandle(token)) { - handles.push_back(handle); - } - } - } - } - - void fillHandles(edm::LuminosityBlock const& lumi, std::vector>& handles) const { - handles.clear(); - if (branchType_ == edm::InLumi) { - handles.reserve(tokens_->size()); - for (auto const& token : *tokens_) { - if (auto handle = lumi.getHandle(token)) { - handles.push_back(handle); - } - } - } - } - - void fillHandles(edm::Run const& run, std::vector>& handles) const { - handles.clear(); - if (branchType_ == edm::InRun) { - handles.reserve(tokens_->size()); - for (auto const& token : *tokens_) { - if (auto handle = run.getHandle(token)) { - handles.push_back(handle); - } - } - } - } - - void fillHandles(edm::ProcessBlock const& processBlock, std::vector>& handles) const { + template + void fillHandles(ProductContainer const& productContainer, std::vector>& handles) const { handles.clear(); - if (branchType_ == edm::InProcess) { + if (branchType_ == BranchTypeForContainerType::branchType) { handles.reserve(tokens_->size()); for (auto const& token : *tokens_) { - if (auto handle = processBlock.getHandle(token)) { + if (auto handle = productContainer.getHandle(token)) { handles.push_back(handle); } } diff --git a/FWCore/Framework/interface/OutputModuleCore.h b/FWCore/Framework/interface/OutputModuleCore.h index dcf201bf91fec..65b8169d655b9 100644 --- a/FWCore/Framework/interface/OutputModuleCore.h +++ b/FWCore/Framework/interface/OutputModuleCore.h @@ -20,6 +20,7 @@ // system include files #include +#include #include #include #include @@ -28,6 +29,7 @@ #include // user include files +#include "DataFormats/Provenance/interface/BranchDescription.h" #include "DataFormats/Provenance/interface/BranchID.h" #include "DataFormats/Provenance/interface/BranchIDList.h" #include "DataFormats/Provenance/interface/ModuleDescription.h" @@ -112,6 +114,10 @@ namespace edm { const ModuleDescription& moduleDescription() const { return moduleDescription_; } + void callWhenNewProductsRegistered(std::function const& func) { + callWhenNewProductsRegistered_ = func; + } + protected: ModuleDescription const& description() const; @@ -190,6 +196,8 @@ namespace edm { OutputProcessBlockHelper outputProcessBlockHelper_; + std::function callWhenNewProductsRegistered_; + //------------------------------------------------------------------ // private member functions //------------------------------------------------------------------ @@ -207,7 +215,7 @@ namespace edm { /// Tell the OutputModule that is must end the current file. void doCloseFile(); - void registerProductsAndCallbacks(OutputModuleCore const*, ProductRegistry const*) {} + void registerProductsAndCallbacks(OutputModuleCore const*, ProductRegistry*); bool needToRunSelection() const; std::vector productsUsedBySelection() const; diff --git a/FWCore/Framework/interface/global/OutputModuleBase.h b/FWCore/Framework/interface/global/OutputModuleBase.h index 0b7dbf36c1a51..7ed8dbd6ca1b8 100644 --- a/FWCore/Framework/interface/global/OutputModuleBase.h +++ b/FWCore/Framework/interface/global/OutputModuleBase.h @@ -71,8 +71,6 @@ namespace edm { private: std::string workerType() const { return "WorkerT"; } - void registerProductsAndCallbacks(OutputModuleBase const*, ProductRegistry const*) {} - virtual void preallocStreams(unsigned int) {} virtual void preallocate(PreallocationConfiguration const&) {} virtual void doBeginStream_(StreamID) {} diff --git a/FWCore/Framework/interface/limited/OutputModuleBase.h b/FWCore/Framework/interface/limited/OutputModuleBase.h index 03ab172ea65e3..adbcfa7556dfc 100644 --- a/FWCore/Framework/interface/limited/OutputModuleBase.h +++ b/FWCore/Framework/interface/limited/OutputModuleBase.h @@ -77,8 +77,6 @@ namespace edm { std::string workerType() const { return "WorkerT"; } - void registerProductsAndCallbacks(OutputModuleBase const*, ProductRegistry const*) {} - virtual void preallocStreams(unsigned int) {} virtual void preallocate(PreallocationConfiguration const&) {} virtual void doBeginStream_(StreamID) {} diff --git a/FWCore/Framework/interface/one/OutputModuleBase.h b/FWCore/Framework/interface/one/OutputModuleBase.h index faed03c77751e..1c9884f4f5ee9 100644 --- a/FWCore/Framework/interface/one/OutputModuleBase.h +++ b/FWCore/Framework/interface/one/OutputModuleBase.h @@ -79,8 +79,6 @@ namespace edm { std::string workerType() const { return "WorkerT"; } - void registerProductsAndCallbacks(OutputModuleBase const*, ProductRegistry const*) {} - virtual void preActionBeforeRunEventAsync(WaitingTaskHolder iTask, ModuleCallingContext const& iModuleCallingContext, Principal const& iPrincipal) const {} diff --git a/FWCore/Framework/src/OutputModuleCore.cc b/FWCore/Framework/src/OutputModuleCore.cc index 6e73deaed3f43..a72d8f00738af 100644 --- a/FWCore/Framework/src/OutputModuleCore.cc +++ b/FWCore/Framework/src/OutputModuleCore.cc @@ -23,6 +23,7 @@ #include "DataFormats/Provenance/interface/BranchKey.h" #include "DataFormats/Provenance/interface/ProductRegistry.h" #include "DataFormats/Provenance/interface/ThinnedAssociationsHelper.h" +#include "FWCore/Framework/interface/ConstProductRegistry.h" #include "FWCore/Framework/interface/EventForOutput.h" #include "FWCore/Framework/interface/EventPrincipal.h" #include "FWCore/Framework/src/insertSelectedProcesses.h" @@ -256,6 +257,15 @@ namespace edm { void OutputModuleCore::doEndJob() { endJob(); } + void OutputModuleCore::registerProductsAndCallbacks(OutputModuleCore const*, ProductRegistry* reg) { + if (callWhenNewProductsRegistered_) { + reg->callForEachBranch(callWhenNewProductsRegistered_); + + Service regService; + regService->watchProductAdditions(callWhenNewProductsRegistered_); + } + } + bool OutputModuleCore::needToRunSelection() const { return !wantAllEvents_; } std::vector OutputModuleCore::productsUsedBySelection() const { diff --git a/FWCore/Integration/plugins/BuildFile.xml b/FWCore/Integration/plugins/BuildFile.xml index 400d9fb31df95..15ae5451dc2b0 100644 --- a/FWCore/Integration/plugins/BuildFile.xml +++ b/FWCore/Integration/plugins/BuildFile.xml @@ -7,7 +7,7 @@ - diff --git a/FWCore/Integration/plugins/TestOutputWithGetterOfProducts.cc b/FWCore/Integration/plugins/TestOutputWithGetterOfProducts.cc new file mode 100644 index 0000000000000..70a312af6cff8 --- /dev/null +++ b/FWCore/Integration/plugins/TestOutputWithGetterOfProducts.cc @@ -0,0 +1,141 @@ +// -*- C++ -*- +// +// Package: FWCore/Integration +// Class: TestOutputWithGetterOfProducts +// +/**\class edm::TestOutputWithGetterOfProducts + + Description: Test GetterOfProducts with OutputModule +*/ +// Original Author: W. David Dagenhart +// Created: 26 April 2023 + +#include "DataFormats/Common/interface/Handle.h" +#include "DataFormats/TestObjects/interface/ThingCollection.h" +#include "FWCore/Framework/interface/Frameworkfwd.h" +#include "FWCore/Framework/interface/GetterOfProducts.h" +#include "FWCore/Framework/interface/MakerMacros.h" +#include "FWCore/Framework/interface/one/OutputModule.h" +#include "FWCore/Framework/interface/TypeMatch.h" +#include "FWCore/ParameterSet/interface/ConfigurationDescriptions.h" +#include "FWCore/ParameterSet/interface/ParameterSet.h" +#include "FWCore/ParameterSet/interface/ParameterSetDescription.h" +#include "FWCore/Utilities/interface/BranchType.h" +#include "FWCore/Utilities/interface/Exception.h" + +#include + +namespace edm { + + class TestOutputWithGetterOfProducts : public one::OutputModule, LuminosityBlockCache> { + public: + explicit TestOutputWithGetterOfProducts(ParameterSet const&); + static void fillDescriptions(ConfigurationDescriptions&); + + private: + void write(EventForOutput const&) override; + void writeLuminosityBlock(LuminosityBlockForOutput const&) override; + void writeRun(RunForOutput const&) override; + + std::shared_ptr globalBeginRun(RunForOutput const&) const override; + void globalEndRun(RunForOutput const&) override; + + std::shared_ptr globalBeginLuminosityBlock(LuminosityBlockForOutput const&) const override; + void globalEndLuminosityBlock(LuminosityBlockForOutput const&) override; + void endJob() override; + + int sumThings(std::vector> const& collections) const; + + unsigned int sum_ = 0; + unsigned int expectedSum_; + GetterOfProducts getterOfProductsRun_; + GetterOfProducts getterOfProductsLumi_; + GetterOfProducts getterOfProductsEvent_; + }; + + TestOutputWithGetterOfProducts::TestOutputWithGetterOfProducts(ParameterSet const& pset) + : one::OutputModuleBase(pset), + one::OutputModule, LuminosityBlockCache>(pset), + expectedSum_(pset.getUntrackedParameter("expectedSum")), + getterOfProductsRun_(TypeMatch(), this, InRun), + getterOfProductsLumi_(edm::TypeMatch(), this, InLumi), + getterOfProductsEvent_(edm::TypeMatch(), this) { + callWhenNewProductsRegistered([this](edm::BranchDescription const& bd) { + getterOfProductsRun_(bd); + getterOfProductsLumi_(bd); + getterOfProductsEvent_(bd); + }); + } + + void TestOutputWithGetterOfProducts::fillDescriptions(ConfigurationDescriptions& descriptions) { + ParameterSetDescription desc; + OutputModule::fillDescription(desc); + desc.addUntracked("expectedSum", 0); + descriptions.addDefault(desc); + } + + void TestOutputWithGetterOfProducts::write(EventForOutput const& event) { + std::vector> handles; + getterOfProductsEvent_.fillHandles(event, handles); + sum_ += sumThings(handles); + } + + void TestOutputWithGetterOfProducts::writeLuminosityBlock(LuminosityBlockForOutput const& lumi) { + std::vector> handles; + getterOfProductsLumi_.fillHandles(lumi, handles); + sum_ += sumThings(handles); + } + + void TestOutputWithGetterOfProducts::writeRun(RunForOutput const& run) { + std::vector> handles; + getterOfProductsRun_.fillHandles(run, handles); + sum_ += sumThings(handles); + } + + std::shared_ptr TestOutputWithGetterOfProducts::globalBeginRun(RunForOutput const& run) const { + std::vector> handles; + getterOfProductsRun_.fillHandles(run, handles); + return std::make_shared(sumThings(handles)); + } + + void TestOutputWithGetterOfProducts::globalEndRun(RunForOutput const& run) { + sum_ += *runCache(run.index()); + std::vector> handles; + getterOfProductsRun_.fillHandles(run, handles); + sum_ += sumThings(handles); + } + + std::shared_ptr TestOutputWithGetterOfProducts::globalBeginLuminosityBlock( + LuminosityBlockForOutput const& lumi) const { + std::vector> handles; + getterOfProductsLumi_.fillHandles(lumi, handles); + return std::make_shared(sumThings(handles)); + } + + void TestOutputWithGetterOfProducts::globalEndLuminosityBlock(LuminosityBlockForOutput const& lumi) { + sum_ += *luminosityBlockCache(lumi.index()); + std::vector> handles; + getterOfProductsLumi_.fillHandles(lumi, handles); + sum_ += sumThings(handles); + } + + void TestOutputWithGetterOfProducts::endJob() { + if (expectedSum_ != 0 && expectedSum_ != sum_) { + throw cms::Exception("TestFailure") << "TestOutputWithGetterOfProducts::endJob, sum = " << sum_ + << " which is not equal to the expected value " << expectedSum_; + } + } + + int TestOutputWithGetterOfProducts::sumThings(std::vector> const& collections) const { + int sum = 0; + for (auto const& collection : collections) { + for (auto const& thing : *collection) { + sum += thing.a; + } + } + return sum; + } +} // namespace edm + +using edm::TestOutputWithGetterOfProducts; +DEFINE_FWK_MODULE(TestOutputWithGetterOfProducts); diff --git a/FWCore/Integration/plugins/TestOutputWithGetterOfProductsGlobal.cc b/FWCore/Integration/plugins/TestOutputWithGetterOfProductsGlobal.cc new file mode 100644 index 0000000000000..b4939b937e948 --- /dev/null +++ b/FWCore/Integration/plugins/TestOutputWithGetterOfProductsGlobal.cc @@ -0,0 +1,143 @@ +// -*- C++ -*- +// +// Package: FWCore/Integration +// Class: TestOutputWithGetterOfProductsGlobal +// +/**\class edm::TestOutputWithGetterOfProductsGlobal + + Description: Test GetterOfProducts with OutputModule +*/ +// Original Author: W. David Dagenhart +// Created: 26 April 2023 + +#include "DataFormats/Common/interface/Handle.h" +#include "DataFormats/TestObjects/interface/ThingCollection.h" +#include "FWCore/Framework/interface/Frameworkfwd.h" +#include "FWCore/Framework/interface/GetterOfProducts.h" +#include "FWCore/Framework/interface/MakerMacros.h" +#include "FWCore/Framework/interface/global/OutputModule.h" +#include "FWCore/Framework/interface/TypeMatch.h" +#include "FWCore/ParameterSet/interface/ConfigurationDescriptions.h" +#include "FWCore/ParameterSet/interface/ParameterSet.h" +#include "FWCore/ParameterSet/interface/ParameterSetDescription.h" +#include "FWCore/Utilities/interface/BranchType.h" +#include "FWCore/Utilities/interface/Exception.h" + +#include +#include + +namespace edm { + + class TestOutputWithGetterOfProductsGlobal : public global::OutputModule, LuminosityBlockCache> { + public: + explicit TestOutputWithGetterOfProductsGlobal(ParameterSet const&); + static void fillDescriptions(ConfigurationDescriptions&); + + private: + void write(EventForOutput const&) override; + void writeLuminosityBlock(LuminosityBlockForOutput const&) override; + void writeRun(RunForOutput const&) override; + + std::shared_ptr globalBeginRun(RunForOutput const&) const override; + void globalEndRun(RunForOutput const&) const override; + + std::shared_ptr globalBeginLuminosityBlock(LuminosityBlockForOutput const&) const override; + void globalEndLuminosityBlock(LuminosityBlockForOutput const&) const override; + void endJob() override; + + int sumThings(std::vector> const& collections) const; + + mutable std::atomic sum_ = 0; + unsigned int expectedSum_; + GetterOfProducts getterOfProductsRun_; + GetterOfProducts getterOfProductsLumi_; + GetterOfProducts getterOfProductsEvent_; + }; + + TestOutputWithGetterOfProductsGlobal::TestOutputWithGetterOfProductsGlobal(ParameterSet const& pset) + : global::OutputModuleBase(pset), + global::OutputModule, LuminosityBlockCache>(pset), + expectedSum_(pset.getUntrackedParameter("expectedSum")), + getterOfProductsRun_(TypeMatch(), this, InRun), + getterOfProductsLumi_(edm::TypeMatch(), this, InLumi), + getterOfProductsEvent_(edm::TypeMatch(), this) { + callWhenNewProductsRegistered([this](edm::BranchDescription const& bd) { + getterOfProductsRun_(bd); + getterOfProductsLumi_(bd); + getterOfProductsEvent_(bd); + }); + } + + void TestOutputWithGetterOfProductsGlobal::fillDescriptions(ConfigurationDescriptions& descriptions) { + ParameterSetDescription desc; + OutputModule::fillDescription(desc); + desc.addUntracked("expectedSum", 0); + descriptions.addDefault(desc); + } + + void TestOutputWithGetterOfProductsGlobal::write(EventForOutput const& event) { + std::vector> handles; + getterOfProductsEvent_.fillHandles(event, handles); + sum_ += sumThings(handles); + } + + void TestOutputWithGetterOfProductsGlobal::writeLuminosityBlock(LuminosityBlockForOutput const& lumi) { + std::vector> handles; + getterOfProductsLumi_.fillHandles(lumi, handles); + sum_ += sumThings(handles); + } + + void TestOutputWithGetterOfProductsGlobal::writeRun(RunForOutput const& run) { + std::vector> handles; + getterOfProductsRun_.fillHandles(run, handles); + sum_ += sumThings(handles); + } + + std::shared_ptr TestOutputWithGetterOfProductsGlobal::globalBeginRun(RunForOutput const& run) const { + std::vector> handles; + getterOfProductsRun_.fillHandles(run, handles); + return std::make_shared(sumThings(handles)); + } + + void TestOutputWithGetterOfProductsGlobal::globalEndRun(RunForOutput const& run) const { + sum_ += *runCache(run.index()); + std::vector> handles; + getterOfProductsRun_.fillHandles(run, handles); + sum_ += sumThings(handles); + } + + std::shared_ptr TestOutputWithGetterOfProductsGlobal::globalBeginLuminosityBlock( + LuminosityBlockForOutput const& lumi) const { + std::vector> handles; + getterOfProductsLumi_.fillHandles(lumi, handles); + return std::make_shared(sumThings(handles)); + } + + void TestOutputWithGetterOfProductsGlobal::globalEndLuminosityBlock(LuminosityBlockForOutput const& lumi) const { + sum_ += *luminosityBlockCache(lumi.index()); + std::vector> handles; + getterOfProductsLumi_.fillHandles(lumi, handles); + sum_ += sumThings(handles); + } + + void TestOutputWithGetterOfProductsGlobal::endJob() { + if (expectedSum_ != 0 && expectedSum_ != sum_.load()) { + throw cms::Exception("TestFailure") << "TestOutputWithGetterOfProductsGlobal::endJob, sum = " << sum_.load() + << " which is not equal to the expected value " << expectedSum_; + } + } + + int TestOutputWithGetterOfProductsGlobal::sumThings( + std::vector> const& collections) const { + int sum = 0; + for (auto const& collection : collections) { + for (auto const& thing : *collection) { + sum += thing.a; + } + } + return sum; + } +} // namespace edm + +using edm::TestOutputWithGetterOfProductsGlobal; +DEFINE_FWK_MODULE(TestOutputWithGetterOfProductsGlobal); diff --git a/FWCore/Integration/plugins/TestOutputWithGetterOfProductsLimited.cc b/FWCore/Integration/plugins/TestOutputWithGetterOfProductsLimited.cc new file mode 100644 index 0000000000000..c49b02660bb23 --- /dev/null +++ b/FWCore/Integration/plugins/TestOutputWithGetterOfProductsLimited.cc @@ -0,0 +1,143 @@ +// -*- C++ -*- +// +// Package: FWCore/Integration +// Class: TestOutputWithGetterOfProductsLimited +// +/**\class edm::TestOutputWithGetterOfProductsLimited + + Description: Test GetterOfProducts with OutputModule +*/ +// Original Author: W. David Dagenhart +// Created: 26 April 2023 + +#include "DataFormats/Common/interface/Handle.h" +#include "DataFormats/TestObjects/interface/ThingCollection.h" +#include "FWCore/Framework/interface/Frameworkfwd.h" +#include "FWCore/Framework/interface/GetterOfProducts.h" +#include "FWCore/Framework/interface/MakerMacros.h" +#include "FWCore/Framework/interface/limited/OutputModule.h" +#include "FWCore/Framework/interface/TypeMatch.h" +#include "FWCore/ParameterSet/interface/ConfigurationDescriptions.h" +#include "FWCore/ParameterSet/interface/ParameterSet.h" +#include "FWCore/ParameterSet/interface/ParameterSetDescription.h" +#include "FWCore/Utilities/interface/BranchType.h" +#include "FWCore/Utilities/interface/Exception.h" + +#include +#include + +namespace edm { + + class TestOutputWithGetterOfProductsLimited : public limited::OutputModule, LuminosityBlockCache> { + public: + explicit TestOutputWithGetterOfProductsLimited(ParameterSet const&); + static void fillDescriptions(ConfigurationDescriptions&); + + private: + void write(EventForOutput const&) override; + void writeLuminosityBlock(LuminosityBlockForOutput const&) override; + void writeRun(RunForOutput const&) override; + + std::shared_ptr globalBeginRun(RunForOutput const&) const override; + void globalEndRun(RunForOutput const&) const override; + + std::shared_ptr globalBeginLuminosityBlock(LuminosityBlockForOutput const&) const override; + void globalEndLuminosityBlock(LuminosityBlockForOutput const&) const override; + void endJob() override; + + int sumThings(std::vector> const& collections) const; + + mutable std::atomic sum_ = 0; + unsigned int expectedSum_; + GetterOfProducts getterOfProductsRun_; + GetterOfProducts getterOfProductsLumi_; + GetterOfProducts getterOfProductsEvent_; + }; + + TestOutputWithGetterOfProductsLimited::TestOutputWithGetterOfProductsLimited(ParameterSet const& pset) + : limited::OutputModuleBase(pset), + limited::OutputModule, LuminosityBlockCache>(pset), + expectedSum_(pset.getUntrackedParameter("expectedSum")), + getterOfProductsRun_(TypeMatch(), this, InRun), + getterOfProductsLumi_(edm::TypeMatch(), this, InLumi), + getterOfProductsEvent_(edm::TypeMatch(), this) { + callWhenNewProductsRegistered([this](edm::BranchDescription const& bd) { + getterOfProductsRun_(bd); + getterOfProductsLumi_(bd); + getterOfProductsEvent_(bd); + }); + } + + void TestOutputWithGetterOfProductsLimited::fillDescriptions(ConfigurationDescriptions& descriptions) { + ParameterSetDescription desc; + OutputModule::fillDescription(desc); + desc.addUntracked("expectedSum", 0); + descriptions.addDefault(desc); + } + + void TestOutputWithGetterOfProductsLimited::write(EventForOutput const& event) { + std::vector> handles; + getterOfProductsEvent_.fillHandles(event, handles); + sum_ += sumThings(handles); + } + + void TestOutputWithGetterOfProductsLimited::writeLuminosityBlock(LuminosityBlockForOutput const& lumi) { + std::vector> handles; + getterOfProductsLumi_.fillHandles(lumi, handles); + sum_ += sumThings(handles); + } + + void TestOutputWithGetterOfProductsLimited::writeRun(RunForOutput const& run) { + std::vector> handles; + getterOfProductsRun_.fillHandles(run, handles); + sum_ += sumThings(handles); + } + + std::shared_ptr TestOutputWithGetterOfProductsLimited::globalBeginRun(RunForOutput const& run) const { + std::vector> handles; + getterOfProductsRun_.fillHandles(run, handles); + return std::make_shared(sumThings(handles)); + } + + void TestOutputWithGetterOfProductsLimited::globalEndRun(RunForOutput const& run) const { + sum_ += *runCache(run.index()); + std::vector> handles; + getterOfProductsRun_.fillHandles(run, handles); + sum_ += sumThings(handles); + } + + std::shared_ptr TestOutputWithGetterOfProductsLimited::globalBeginLuminosityBlock( + LuminosityBlockForOutput const& lumi) const { + std::vector> handles; + getterOfProductsLumi_.fillHandles(lumi, handles); + return std::make_shared(sumThings(handles)); + } + + void TestOutputWithGetterOfProductsLimited::globalEndLuminosityBlock(LuminosityBlockForOutput const& lumi) const { + sum_ += *luminosityBlockCache(lumi.index()); + std::vector> handles; + getterOfProductsLumi_.fillHandles(lumi, handles); + sum_ += sumThings(handles); + } + + void TestOutputWithGetterOfProductsLimited::endJob() { + if (expectedSum_ != 0 && expectedSum_ != sum_.load()) { + throw cms::Exception("TestFailure") << "TestOutputWithGetterOfProductsLimited::endJob, sum = " << sum_.load() + << " which is not equal to the expected value " << expectedSum_; + } + } + + int TestOutputWithGetterOfProductsLimited::sumThings( + std::vector> const& collections) const { + int sum = 0; + for (auto const& collection : collections) { + for (auto const& thing : *collection) { + sum += thing.a; + } + } + return sum; + } +} // namespace edm + +using edm::TestOutputWithGetterOfProductsLimited; +DEFINE_FWK_MODULE(TestOutputWithGetterOfProductsLimited); diff --git a/FWCore/Integration/test/run_TestGetBy.sh b/FWCore/Integration/test/run_TestGetBy.sh index 4091148592073..6fdb8d4512c15 100755 --- a/FWCore/Integration/test/run_TestGetBy.sh +++ b/FWCore/Integration/test/run_TestGetBy.sh @@ -52,4 +52,7 @@ LOCAL_TEST_DIR=${SCRAM_TEST_PATH} echo "testGetByWithEmptyRun_cfg.py" cmsRun -p ${LOCAL_TEST_DIR}/testGetByWithEmptyRun_cfg.py || die "cmsRun testGetByWithEmptyRun_cfg.py" $? + echo "testGetterOfProductsWithOutputModule_cfg.py" + cmsRun -p ${LOCAL_TEST_DIR}/testGetterOfProductsWithOutputModule_cfg.py || die "cmsRun testGetterOfProductsWithOutputModule_cfg.py" $? + exit 0 diff --git a/FWCore/Integration/test/testGetterOfProductsWithOutputModule_cfg.py b/FWCore/Integration/test/testGetterOfProductsWithOutputModule_cfg.py new file mode 100644 index 0000000000000..707ccb387d039 --- /dev/null +++ b/FWCore/Integration/test/testGetterOfProductsWithOutputModule_cfg.py @@ -0,0 +1,41 @@ +import FWCore.ParameterSet.Config as cms + +process = cms.Process("TEST") + +process.source = cms.Source("EmptySource") +process.maxEvents.input = 3 + +process.thing = cms.EDProducer("ThingProducer", + nThings = cms.int32(4) +) + +process.testOne = cms.OutputModule("TestOutputWithGetterOfProducts", + # 6 in one ThingCollection (0 + 1 + 2 + 3) + # 6 * (3 writeEvent + 1 writeLumi * 2 (begin + end) + 1 writeRun * 2 (begin + end)) = 42 for writes + # 6 * (1 endLumi * 2 (begin + end) + 1 endRun * 2 (begin + end)) = 24 for end transitions + # 6 * (1 beginLumi * 1 (begin) + 1 beginRun * 2 (begin)) = 12 for begin transitions + # 42 + 24 + 12 = 78 + expectedSum = cms.untracked.uint32(78) +) + +process.testGlobal = cms.OutputModule("TestOutputWithGetterOfProductsGlobal", + # 6 in one ThingCollection (0 + 1 + 2 + 3) + # 6 * (3 writeEvent + 1 writeLumi * 2 (begin + end) + 1 writeRun * 2 (begin + end)) = 42 for writes + # 6 * (1 endLumi * 2 (begin + end) + 1 endRun * 2 (begin + end)) = 24 for end transitions + # 6 * (1 beginLumi * 1 (begin) + 1 beginRun * 2 (begin)) = 12 for begin transitions + # 42 + 24 + 12 = 78 + expectedSum = cms.untracked.uint32(78) +) + +process.testLimited = cms.OutputModule("TestOutputWithGetterOfProductsLimited", + # 6 in one ThingCollection (0 + 1 + 2 + 3) + # 6 * (3 writeEvent + 1 writeLumi * 2 (begin + end) + 1 writeRun * 2 (begin + end)) = 42 for writes + # 6 * (1 endLumi * 2 (begin + end) + 1 endRun * 2 (begin + end)) = 24 for end transitions + # 6 * (1 beginLumi * 1 (begin) + 1 beginRun * 2 (begin)) = 12 for begin transitions + # 42 + 24 + 12 = 78 + expectedSum = cms.untracked.uint32(78) +) + +process.path = cms.Path(process.thing) + +process.endPath = cms.EndPath(process.testOne * process.testGlobal * process.testLimited)