Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2022-10-13 03:38:04

0001 
0002 /*----------------------------------------------------------------------
0003 
0004 Toy edm::stream::EDProducer modules of
0005 edm::*Cache templates and edm::*Producer classes
0006 for testing purposes only.
0007 
0008 ----------------------------------------------------------------------*/
0009 
0010 #include <atomic>
0011 #include <functional>
0012 #include <iostream>
0013 #include <map>
0014 #include <tuple>
0015 #include <unistd.h>
0016 #include <vector>
0017 
0018 #include "FWCore/Framework/interface/CacheHandle.h"
0019 #include "FWCore/Framework/interface/stream/EDProducer.h"
0020 #include "FWCore/Framework/interface/maker/WorkerT.h"
0021 #include "FWCore/Framework/interface/HistoryAppender.h"
0022 #include "FWCore/MessageLogger/interface/MessageLogger.h"
0023 #include "FWCore/ServiceRegistry/interface/ParentContext.h"
0024 #include "FWCore/ServiceRegistry/interface/StreamContext.h"
0025 #include "FWCore/Utilities/interface/GlobalIdentifier.h"
0026 #include "FWCore/Framework/interface/Event.h"
0027 #include "FWCore/Framework/interface/MakerMacros.h"
0028 #include "FWCore/Framework/interface/ProcessBlock.h"
0029 #include "FWCore/ParameterSet/interface/ParameterSet.h"
0030 #include "FWCore/Utilities/interface/EDMException.h"
0031 #include "DataFormats/TestObjects/interface/ToyProducts.h"
0032 
0033 namespace edmtest {
0034   namespace stream {
0035 
0036     // anonymous namespace here causes build warnings
0037     namespace cache {
0038       struct Cache {
0039         Cache() : value(0), run(0), lumi(0) {}
0040         //Using mutable since we want to update the value.
0041         mutable std::atomic<unsigned int> value;
0042         mutable std::atomic<unsigned int> run;
0043         mutable std::atomic<unsigned int> lumi;
0044       };
0045 
0046       struct SummaryCache {
0047         // Intentionally not thread safe, not atomic
0048         unsigned int value = 0;
0049       };
0050 
0051       struct TestGlobalCache {
0052         CMS_THREAD_SAFE mutable edm::EDPutTokenT<unsigned int> token_;
0053         CMS_THREAD_SAFE mutable edm::EDGetTokenT<unsigned int> getTokenBegin_;
0054         CMS_THREAD_SAFE mutable edm::EDGetTokenT<unsigned int> getTokenEnd_;
0055         unsigned int trans_{0};
0056         mutable std::atomic<unsigned int> m_count{0};
0057       };
0058 
0059     }  // namespace cache
0060 
0061     using Cache = cache::Cache;
0062     using SummaryCache = cache::SummaryCache;
0063     using TestGlobalCache = cache::TestGlobalCache;
0064 
0065     class GlobalIntProducer : public edm::stream::EDProducer<edm::GlobalCache<Cache>> {
0066     public:
0067       static std::atomic<unsigned int> m_count;
0068       unsigned int trans_;
0069       static std::atomic<unsigned int> cvalue_;
0070 
0071       static std::unique_ptr<Cache> initializeGlobalCache(edm::ParameterSet const&) {
0072         ++m_count;
0073         return std::make_unique<Cache>();
0074       }
0075 
0076       GlobalIntProducer(edm::ParameterSet const& p, const Cache* iGlobal) {
0077         trans_ = p.getParameter<int>("transitions");
0078         cvalue_ = p.getParameter<int>("cachevalue");
0079         produces<unsigned int>();
0080       }
0081 
0082       static void globalBeginJob(Cache* iGlobal) {
0083         ++m_count;
0084         if (iGlobal->value != 0) {
0085           throw cms::Exception("cache value") << iGlobal->value << " but it was supposed to be 0";
0086         }
0087       }
0088 
0089       void produce(edm::Event&, edm::EventSetup const&) override {
0090         ++m_count;
0091         ++((globalCache())->value);
0092       }
0093 
0094       static void globalEndJob(Cache* iGlobal) {
0095         ++m_count;
0096         if (iGlobal->value != cvalue_) {
0097           throw cms::Exception("cache value") << iGlobal->value << " but it was supposed to be " << cvalue_;
0098         }
0099       }
0100 
0101       ~GlobalIntProducer() {
0102         if (m_count != trans_) {
0103           throw cms::Exception("transitions") << m_count << " but it was supposed to be " << trans_;
0104         }
0105       }
0106     };
0107 
0108     class RunIntProducer : public edm::stream::EDProducer<edm::RunCache<Cache>> {
0109     public:
0110       static std::atomic<unsigned int> m_count;
0111       unsigned int trans_;
0112       static std::atomic<unsigned int> cvalue_;
0113 
0114       RunIntProducer(edm::ParameterSet const& p) {
0115         trans_ = p.getParameter<int>("transitions");
0116         cvalue_ = p.getParameter<int>("cachevalue");
0117         produces<unsigned int>();
0118       }
0119 
0120       void produce(edm::Event&, edm::EventSetup const&) override {
0121         ++m_count;
0122         ++(runCache()->value);
0123       }
0124 
0125       static std::shared_ptr<Cache> globalBeginRun(edm::Run const& iRun, edm::EventSetup const&, GlobalCache const*) {
0126         ++m_count;
0127         auto pCache = std::make_shared<Cache>();
0128         pCache->run = iRun.runAuxiliary().run();
0129         return pCache;
0130       }
0131 
0132       void beginRun(edm::Run const& iRun, edm::EventSetup const&) override {
0133         if (runCache()->run != iRun.runAuxiliary().run()) {
0134           throw cms::Exception("begin out of sequence") << "beginRun seen before globalBeginRun";
0135         }
0136       }
0137 
0138       static void globalEndRun(edm::Run const& iRun, edm::EventSetup const&, RunContext const* iContext) {
0139         ++m_count;
0140         auto pCache = iContext->run();
0141         if (pCache->run != iRun.runAuxiliary().run()) {
0142           throw cms::Exception("end out of sequence") << "globalEndRun seen before globalBeginRun in Run" << iRun.run();
0143         }
0144         pCache->run = 0;
0145         if (iContext->run()->value != cvalue_) {
0146           throw cms::Exception("cache value") << iContext->run()->value << " but it was supposed to be " << cvalue_;
0147         }
0148       }
0149 
0150       void endRun(edm::Run const& iRun, edm::EventSetup const&) override {
0151         if (runCache()->run != iRun.runAuxiliary().run()) {
0152           throw cms::Exception("end out of sequence") << "globalEndRun seen before endRun";
0153         }
0154       }
0155 
0156       ~RunIntProducer() {
0157         if (m_count != trans_) {
0158           throw cms::Exception("transitions") << m_count << " but it was supposed to be " << trans_;
0159         }
0160       }
0161     };
0162 
0163     class LumiIntProducer : public edm::stream::EDProducer<edm::LuminosityBlockCache<Cache>> {
0164     public:
0165       static std::atomic<unsigned int> m_count;
0166       unsigned int trans_;
0167       static std::atomic<unsigned int> cvalue_;
0168 
0169       LumiIntProducer(edm::ParameterSet const& p) {
0170         trans_ = p.getParameter<int>("transitions");
0171         cvalue_ = p.getParameter<int>("cachevalue");
0172         produces<unsigned int>();
0173       }
0174 
0175       void produce(edm::Event&, edm::EventSetup const&) override {
0176         ++m_count;
0177         ++(luminosityBlockCache()->value);
0178       }
0179 
0180       static std::shared_ptr<Cache> globalBeginLuminosityBlock(edm::LuminosityBlock const& iLB,
0181                                                                edm::EventSetup const&,
0182                                                                RunContext const*) {
0183         ++m_count;
0184         auto pCache = std::make_shared<Cache>();
0185         pCache->run = iLB.luminosityBlockAuxiliary().run();
0186         pCache->lumi = iLB.luminosityBlockAuxiliary().luminosityBlock();
0187         return pCache;
0188       }
0189 
0190       void beginLuminosityBlock(edm::LuminosityBlock const& iLB, edm::EventSetup const&) override {
0191         if (luminosityBlockCache()->run != iLB.luminosityBlockAuxiliary().run() ||
0192             luminosityBlockCache()->lumi != iLB.luminosityBlockAuxiliary().luminosityBlock()) {
0193           throw cms::Exception("begin out of sequence")
0194               << "beginLuminosityBlock seen before globalBeginLuminosityBlock " << luminosityBlockCache()->run << " "
0195               << iLB.luminosityBlockAuxiliary().run();
0196         }
0197       }
0198 
0199       static void globalEndLuminosityBlock(edm::LuminosityBlock const& iLB,
0200                                            edm::EventSetup const&,
0201                                            LuminosityBlockContext const* iLBContext) {
0202         ++m_count;
0203         auto pCache = iLBContext->luminosityBlock();
0204         if (pCache->run != iLB.luminosityBlockAuxiliary().run() ||
0205             pCache->lumi != iLB.luminosityBlockAuxiliary().luminosityBlock()) {
0206           throw cms::Exception("end out of sequence")
0207               << "globalEndLuminosityBlock seen before globalBeginLuminosityBlock in LuminosityBlock"
0208               << iLB.luminosityBlock();
0209         }
0210         pCache->run = 0;
0211         pCache->lumi = 0;
0212         if (iLBContext->luminosityBlock()->value != cvalue_) {
0213           throw cms::Exception("cache value")
0214               << iLBContext->luminosityBlock()->value << " but it was supposed to be " << cvalue_;
0215         }
0216       }
0217 
0218       void endLuminosityBlock(edm::LuminosityBlock const& iLB, edm::EventSetup const&) override {
0219         if (luminosityBlockCache()->run != iLB.luminosityBlockAuxiliary().run() ||
0220             luminosityBlockCache()->lumi != iLB.luminosityBlockAuxiliary().luminosityBlock()) {
0221           throw cms::Exception("end out of sequence") << "globalEndLuminosityBlock seen before endLuminosityBlock";
0222         }
0223       }
0224 
0225       ~LumiIntProducer() {
0226         if (m_count != trans_) {
0227           throw cms::Exception("transitions") << m_count << " but it was supposed to be " << trans_;
0228         }
0229       }
0230     };
0231 
0232     class RunSummaryIntProducer
0233         : public edm::stream::EDProducer<edm::RunCache<Cache>, edm::RunSummaryCache<SummaryCache>> {
0234     public:
0235       static std::atomic<unsigned int> m_count;
0236       unsigned int trans_;
0237       static std::atomic<unsigned int> cvalue_;
0238       static std::atomic<bool> globalBeginRunCalled_;
0239       unsigned int valueAccumulatedForStream_ = 0;
0240       bool endRunWasCalled_ = false;
0241 
0242       RunSummaryIntProducer(edm::ParameterSet const& p) {
0243         trans_ = p.getParameter<int>("transitions");
0244         cvalue_ = p.getParameter<int>("cachevalue");
0245         produces<unsigned int>();
0246       }
0247 
0248       void beginRun(edm::Run const&, edm::EventSetup const&) override {
0249         valueAccumulatedForStream_ = 0;
0250         endRunWasCalled_ = false;
0251       }
0252 
0253       void produce(edm::Event&, edm::EventSetup const&) override {
0254         ++m_count;
0255         ++(runCache()->value);
0256         ++valueAccumulatedForStream_;
0257       }
0258 
0259       static std::shared_ptr<Cache> globalBeginRun(edm::Run const& iRun, edm::EventSetup const&, GlobalCache const*) {
0260         ++m_count;
0261         globalBeginRunCalled_ = true;
0262         auto pCache = std::make_shared<Cache>();
0263         ++(pCache->run);
0264         return pCache;
0265       }
0266 
0267       static std::shared_ptr<SummaryCache> globalBeginRunSummary(edm::Run const&,
0268                                                                  edm::EventSetup const&,
0269                                                                  GlobalCache const*) {
0270         ++m_count;
0271         if (!globalBeginRunCalled_) {
0272           throw cms::Exception("begin out of sequence") << "globalBeginRunSummary seen before globalBeginRun";
0273         }
0274         globalBeginRunCalled_ = false;
0275         return std::make_shared<SummaryCache>();
0276       }
0277 
0278       void endRunSummary(edm::Run const&, edm::EventSetup const&, SummaryCache* runSummaryCache) const override {
0279         runSummaryCache->value += valueAccumulatedForStream_;
0280         if (!endRunWasCalled_) {
0281           throw cms::Exception("end out of sequence") << "endRunSummary seen before endRun";
0282         }
0283       }
0284 
0285       static void globalEndRunSummary(edm::Run const&,
0286                                       edm::EventSetup const&,
0287                                       RunContext const*,
0288                                       SummaryCache* runSummaryCache) {
0289         ++m_count;
0290         if (runSummaryCache->value != cvalue_) {
0291           throw cms::Exception("unexpectedValue")
0292               << "run summary cache value = " << runSummaryCache->value << " but it was supposed to be " << cvalue_;
0293         }
0294       }
0295 
0296       static void globalEndRun(edm::Run const& iRun, edm::EventSetup const&, RunContext const* iContext) {
0297         ++m_count;
0298         auto pCache = iContext->run();
0299         if (pCache->value != cvalue_) {
0300           throw cms::Exception("unExpectedValue")
0301               << "run cache value " << pCache->value << " but it was supposed to be " << cvalue_;
0302         }
0303         if (pCache->run != 1) {
0304           throw cms::Exception("end out of sequence") << "globalEndRun seen before globalBeginRun in Run" << iRun.run();
0305         }
0306       }
0307 
0308       void endRun(edm::Run const&, edm::EventSetup const&) override { endRunWasCalled_ = true; }
0309 
0310       ~RunSummaryIntProducer() {
0311         if (m_count != trans_) {
0312           throw cms::Exception("transitions") << m_count << " but it was supposed to be " << trans_;
0313         }
0314       }
0315     };
0316 
0317     class LumiSummaryIntProducer : public edm::stream::EDProducer<edm::LuminosityBlockCache<Cache>,
0318                                                                   edm::LuminosityBlockSummaryCache<SummaryCache>> {
0319     public:
0320       static std::atomic<unsigned int> m_count;
0321       unsigned int trans_;
0322       static std::atomic<unsigned int> cvalue_;
0323       static std::atomic<bool> globalBeginLumiCalled_;
0324       unsigned int valueAccumulatedForStream_ = 0;
0325       bool endLumiWasCalled_ = false;
0326 
0327       LumiSummaryIntProducer(edm::ParameterSet const& p) {
0328         trans_ = p.getParameter<int>("transitions");
0329         cvalue_ = p.getParameter<int>("cachevalue");
0330         produces<unsigned int>();
0331       }
0332 
0333       void produce(edm::Event&, edm::EventSetup const&) override {
0334         ++m_count;
0335         ++(luminosityBlockCache()->value);
0336         ++valueAccumulatedForStream_;
0337       }
0338 
0339       void beginLuminosityBlock(edm::LuminosityBlock const&, edm::EventSetup const&) override {
0340         valueAccumulatedForStream_ = 0;
0341         endLumiWasCalled_ = false;
0342       }
0343 
0344       static std::shared_ptr<Cache> globalBeginLuminosityBlock(edm::LuminosityBlock const& iLB,
0345                                                                edm::EventSetup const&,
0346                                                                RunContext const*) {
0347         ++m_count;
0348         globalBeginLumiCalled_ = true;
0349         auto pCache = std::make_shared<Cache>();
0350         ++(pCache->lumi);
0351         return pCache;
0352       }
0353 
0354       static std::shared_ptr<SummaryCache> globalBeginLuminosityBlockSummary(edm::LuminosityBlock const&,
0355                                                                              edm::EventSetup const&,
0356                                                                              LuminosityBlockContext const*) {
0357         ++m_count;
0358         if (!globalBeginLumiCalled_) {
0359           throw cms::Exception("begin out of sequence")
0360               << "globalBeginLuminosityBlockSummary seen before globalBeginLuminosityBlock";
0361         }
0362         globalBeginLumiCalled_ = false;
0363         return std::make_shared<SummaryCache>();
0364       }
0365 
0366       void endLuminosityBlockSummary(edm::LuminosityBlock const&,
0367                                      edm::EventSetup const&,
0368                                      SummaryCache* lumiSummaryCache) const override {
0369         lumiSummaryCache->value += valueAccumulatedForStream_;
0370         if (!endLumiWasCalled_) {
0371           throw cms::Exception("end out of sequence") << "endLuminosityBlockSummary seen before endLuminosityBlock";
0372         }
0373       }
0374 
0375       static void globalEndLuminosityBlockSummary(edm::LuminosityBlock const&,
0376                                                   edm::EventSetup const&,
0377                                                   LuminosityBlockContext const* iLBContext,
0378                                                   SummaryCache* lumiSummaryCache) {
0379         ++m_count;
0380         if (lumiSummaryCache->value != cvalue_) {
0381           throw cms::Exception("unexpectedValue")
0382               << "lumi summary cache value = " << lumiSummaryCache->value << " but it was supposed to be " << cvalue_;
0383         }
0384         auto pCache = iLBContext->luminosityBlock();
0385         // Add one so globalEndLuminosityBlock can check this function was called first
0386         ++pCache->value;
0387       }
0388 
0389       static void globalEndLuminosityBlock(edm::LuminosityBlock const& iLB,
0390                                            edm::EventSetup const&,
0391                                            LuminosityBlockContext const* iLBContext) {
0392         ++m_count;
0393         auto pCache = iLBContext->luminosityBlock();
0394         if (pCache->value != cvalue_ + 1) {
0395           throw cms::Exception("unexpectedValue")
0396               << "lumi cache value " << pCache->value << " but it was supposed to be " << cvalue_ + 1;
0397         }
0398         if (pCache->lumi != 1) {
0399           throw cms::Exception("end out of sequence")
0400               << "globalEndLuminosityBlock seen before globalBeginLuminosityBlock in LuminosityBlock"
0401               << iLB.luminosityBlock();
0402         }
0403       }
0404 
0405       void endLuminosityBlock(edm::LuminosityBlock const&, edm::EventSetup const&) override {
0406         endLumiWasCalled_ = true;
0407       }
0408 
0409       ~LumiSummaryIntProducer() {
0410         if (m_count != trans_) {
0411           throw cms::Exception("transitions") << m_count << " but it was supposed to be " << trans_;
0412         }
0413       }
0414     };
0415 
0416     class ProcessBlockIntProducer
0417         : public edm::stream::EDProducer<edm::WatchProcessBlock, edm::GlobalCache<TestGlobalCache>> {
0418     public:
0419       explicit ProcessBlockIntProducer(edm::ParameterSet const& pset, TestGlobalCache const* testGlobalCache) {
0420         {
0421           auto tag = pset.getParameter<edm::InputTag>("consumesBeginProcessBlock");
0422           if (not tag.label().empty()) {
0423             testGlobalCache->getTokenBegin_ = consumes<unsigned int, edm::InProcess>(tag);
0424           }
0425         }
0426         {
0427           auto tag = pset.getParameter<edm::InputTag>("consumesEndProcessBlock");
0428           if (not tag.label().empty()) {
0429             testGlobalCache->getTokenEnd_ = consumes<unsigned int, edm::InProcess>(tag);
0430           }
0431         }
0432       }
0433 
0434       static std::unique_ptr<TestGlobalCache> initializeGlobalCache(edm::ParameterSet const& pset) {
0435         auto testGlobalCache = std::make_unique<TestGlobalCache>();
0436         testGlobalCache->trans_ = pset.getParameter<int>("transitions");
0437         return testGlobalCache;
0438       }
0439 
0440       static void beginProcessBlock(edm::ProcessBlock const& processBlock, TestGlobalCache* testGlobalCache) {
0441         if (testGlobalCache->m_count != 0) {
0442           throw cms::Exception("transitions") << "ProcessBlockIntProducer::begin transitions "
0443                                               << testGlobalCache->m_count << " but it was supposed to be " << 0;
0444         }
0445         ++testGlobalCache->m_count;
0446 
0447         const unsigned int valueToGet = 51;
0448         if (not testGlobalCache->getTokenBegin_.isUninitialized()) {
0449           if (processBlock.get(testGlobalCache->getTokenBegin_) != valueToGet) {
0450             throw cms::Exception("BadValue")
0451                 << "expected " << valueToGet << " but got " << processBlock.get(testGlobalCache->getTokenBegin_);
0452           }
0453         }
0454       }
0455 
0456       void produce(edm::Event&, edm::EventSetup const&) override {
0457         TestGlobalCache const* testGlobalCache = globalCache();
0458         if (testGlobalCache->m_count < 1u) {
0459           throw cms::Exception("out of sequence") << "produce before beginProcessBlock " << testGlobalCache->m_count;
0460         }
0461         ++testGlobalCache->m_count;
0462       }
0463 
0464       static void endProcessBlock(edm::ProcessBlock const& processBlock, TestGlobalCache* testGlobalCache) {
0465         ++testGlobalCache->m_count;
0466         if (testGlobalCache->m_count != testGlobalCache->trans_) {
0467           throw cms::Exception("transitions") << "ProcessBlockIntProducer::end transitions " << testGlobalCache->m_count
0468                                               << " but it was supposed to be " << testGlobalCache->trans_;
0469         }
0470         {
0471           const unsigned int valueToGet = 51;
0472           if (not testGlobalCache->getTokenBegin_.isUninitialized()) {
0473             if (processBlock.get(testGlobalCache->getTokenBegin_) != valueToGet) {
0474               throw cms::Exception("BadValue")
0475                   << "expected " << valueToGet << " but got " << processBlock.get(testGlobalCache->getTokenBegin_);
0476             }
0477           }
0478         }
0479         {
0480           const unsigned int valueToGet = 61;
0481           if (not testGlobalCache->getTokenEnd_.isUninitialized()) {
0482             if (processBlock.get(testGlobalCache->getTokenEnd_) != valueToGet) {
0483               throw cms::Exception("BadValue")
0484                   << "expected " << valueToGet << " but got " << processBlock.get(testGlobalCache->getTokenEnd_);
0485             }
0486           }
0487         }
0488       }
0489 
0490       static void globalEndJob(TestGlobalCache* testGlobalCache) {
0491         if (testGlobalCache->m_count != testGlobalCache->trans_) {
0492           throw cms::Exception("transitions")
0493               << "TestBeginProcessBlockProducer transitions " << testGlobalCache->m_count
0494               << " but it was supposed to be " << testGlobalCache->trans_;
0495         }
0496       }
0497 
0498       ~ProcessBlockIntProducer() {
0499         TestGlobalCache const* testGlobalCache = globalCache();
0500         if (testGlobalCache->m_count != testGlobalCache->trans_) {
0501           throw cms::Exception("transitions") << "ProcessBlockIntProducer transitions " << testGlobalCache->m_count
0502                                               << " but it was supposed to be " << testGlobalCache->trans_;
0503         }
0504       }
0505     };
0506 
0507     class TestBeginProcessBlockProducer
0508         : public edm::stream::EDProducer<edm::BeginProcessBlockProducer, edm::GlobalCache<TestGlobalCache>> {
0509     public:
0510       explicit TestBeginProcessBlockProducer(edm::ParameterSet const& pset, TestGlobalCache const* testGlobalCache) {
0511         testGlobalCache->token_ = produces<unsigned int, edm::Transition::BeginProcessBlock>("begin");
0512 
0513         auto tag = pset.getParameter<edm::InputTag>("consumesBeginProcessBlock");
0514         if (not tag.label().empty()) {
0515           testGlobalCache->getTokenBegin_ = consumes<unsigned int, edm::InProcess>(tag);
0516         }
0517       }
0518 
0519       static std::unique_ptr<TestGlobalCache> initializeGlobalCache(edm::ParameterSet const& pset) {
0520         auto testGlobalCache = std::make_unique<TestGlobalCache>();
0521         testGlobalCache->trans_ = pset.getParameter<int>("transitions");
0522         return testGlobalCache;
0523       }
0524 
0525       static void beginProcessBlockProduce(edm::ProcessBlock& processBlock, TestGlobalCache const* testGlobalCache) {
0526         if (testGlobalCache->m_count != 0) {
0527           throw cms::Exception("transitions") << "TestBeginProcessBlockProducer transitions "
0528                                               << testGlobalCache->m_count << " but it was supposed to be " << 0;
0529         }
0530         ++testGlobalCache->m_count;
0531 
0532         const unsigned int valueToPutAndGet = 51;
0533         processBlock.emplace(testGlobalCache->token_, valueToPutAndGet);
0534 
0535         if (not testGlobalCache->getTokenBegin_.isUninitialized()) {
0536           if (processBlock.get(testGlobalCache->getTokenBegin_) != valueToPutAndGet) {
0537             throw cms::Exception("BadValue")
0538                 << "expected " << valueToPutAndGet << " but got " << processBlock.get(testGlobalCache->getTokenBegin_);
0539           }
0540         }
0541       }
0542 
0543       void produce(edm::Event&, edm::EventSetup const&) override {
0544         TestGlobalCache const* testGlobalCache = globalCache();
0545         if (testGlobalCache->m_count < 1u) {
0546           throw cms::Exception("out of sequence")
0547               << "produce before beginProcessBlockProduce " << testGlobalCache->m_count;
0548         }
0549         ++testGlobalCache->m_count;
0550       }
0551 
0552       static void globalEndJob(TestGlobalCache* testGlobalCache) {
0553         if (testGlobalCache->m_count != testGlobalCache->trans_) {
0554           throw cms::Exception("transitions")
0555               << "TestBeginProcessBlockProducer transitions " << testGlobalCache->m_count
0556               << " but it was supposed to be " << testGlobalCache->trans_;
0557         }
0558       }
0559 
0560       ~TestBeginProcessBlockProducer() {
0561         TestGlobalCache const* testGlobalCache = globalCache();
0562         if (testGlobalCache->m_count != testGlobalCache->trans_) {
0563           throw cms::Exception("transitions")
0564               << "TestBeginProcessBlockProducer transitions " << testGlobalCache->m_count
0565               << " but it was supposed to be " << testGlobalCache->trans_;
0566         }
0567       }
0568     };
0569 
0570     class TestEndProcessBlockProducer
0571         : public edm::stream::EDProducer<edm::EndProcessBlockProducer, edm::GlobalCache<TestGlobalCache>> {
0572     public:
0573       explicit TestEndProcessBlockProducer(edm::ParameterSet const& pset, TestGlobalCache const* testGlobalCache) {
0574         testGlobalCache->token_ = produces<unsigned int, edm::Transition::EndProcessBlock>("end");
0575 
0576         auto tag = pset.getParameter<edm::InputTag>("consumesEndProcessBlock");
0577         if (not tag.label().empty()) {
0578           testGlobalCache->getTokenEnd_ = consumes<unsigned int, edm::InProcess>(tag);
0579         }
0580       }
0581 
0582       static std::unique_ptr<TestGlobalCache> initializeGlobalCache(edm::ParameterSet const& pset) {
0583         auto testGlobalCache = std::make_unique<TestGlobalCache>();
0584         testGlobalCache->trans_ = pset.getParameter<int>("transitions");
0585         return testGlobalCache;
0586       }
0587 
0588       void produce(edm::Event&, edm::EventSetup const&) override {
0589         TestGlobalCache const* testGlobalCache = globalCache();
0590         ++testGlobalCache->m_count;
0591       }
0592 
0593       static void endProcessBlockProduce(edm::ProcessBlock& processBlock, TestGlobalCache const* testGlobalCache) {
0594         ++testGlobalCache->m_count;
0595         if (testGlobalCache->m_count != testGlobalCache->trans_) {
0596           throw cms::Exception("transitions") << "TestEndProcessBlockProducer transitions " << testGlobalCache->m_count
0597                                               << " but it was supposed to be " << testGlobalCache->trans_;
0598         }
0599         const unsigned int valueToPutAndGet = 61;
0600         processBlock.emplace(testGlobalCache->token_, valueToPutAndGet);
0601 
0602         if (not testGlobalCache->getTokenEnd_.isUninitialized()) {
0603           if (processBlock.get(testGlobalCache->getTokenEnd_) != valueToPutAndGet) {
0604             throw cms::Exception("BadValue")
0605                 << "expected " << valueToPutAndGet << " but got " << processBlock.get(testGlobalCache->getTokenEnd_);
0606           }
0607         }
0608       }
0609 
0610       static void globalEndJob(TestGlobalCache* testGlobalCache) {
0611         if (testGlobalCache->m_count != testGlobalCache->trans_) {
0612           throw cms::Exception("transitions")
0613               << "TestBeginProcessBlockProducer transitions " << testGlobalCache->m_count
0614               << " but it was supposed to be " << testGlobalCache->trans_;
0615         }
0616       }
0617 
0618       ~TestEndProcessBlockProducer() {
0619         TestGlobalCache const* testGlobalCache = globalCache();
0620         if (testGlobalCache->m_count != testGlobalCache->trans_) {
0621           throw cms::Exception("transitions") << "~TestEndProcessBlockProducer transitions " << testGlobalCache->m_count
0622                                               << " but it was supposed to be " << testGlobalCache->trans_;
0623         }
0624       }
0625     };
0626 
0627     class ProcessBlockIntProducerNoGlobalCache : public edm::stream::EDProducer<edm::WatchProcessBlock> {
0628     public:
0629       explicit ProcessBlockIntProducerNoGlobalCache(edm::ParameterSet const&) {}
0630 
0631       static void beginProcessBlock(edm::ProcessBlock const&) {}
0632 
0633       void produce(edm::Event&, edm::EventSetup const&) override {}
0634 
0635       static void endProcessBlock(edm::ProcessBlock const&) {}
0636     };
0637 
0638     class TestBeginProcessBlockProducerNoGlobalCache : public edm::stream::EDProducer<edm::BeginProcessBlockProducer> {
0639     public:
0640       explicit TestBeginProcessBlockProducerNoGlobalCache(edm::ParameterSet const&) {}
0641 
0642       static void beginProcessBlockProduce(edm::ProcessBlock&) {}
0643 
0644       void produce(edm::Event&, edm::EventSetup const&) override {}
0645     };
0646 
0647     class TestEndProcessBlockProducerNoGlobalCache : public edm::stream::EDProducer<edm::EndProcessBlockProducer> {
0648     public:
0649       explicit TestEndProcessBlockProducerNoGlobalCache(edm::ParameterSet const&) {}
0650 
0651       void produce(edm::Event&, edm::EventSetup const&) override {}
0652 
0653       static void endProcessBlockProduce(edm::ProcessBlock&) {}
0654     };
0655 
0656     class TestBeginRunProducer : public edm::stream::EDProducer<edm::RunCache<bool>, edm::BeginRunProducer> {
0657     public:
0658       static std::atomic<unsigned int> m_count;
0659       unsigned int trans_;
0660       static std::atomic<unsigned int> cvalue_;
0661       static std::atomic<bool> gbr;
0662       static std::atomic<bool> ger;
0663       static std::atomic<bool> gbrp;
0664 
0665       TestBeginRunProducer(edm::ParameterSet const& p) {
0666         trans_ = p.getParameter<int>("transitions");
0667         cvalue_ = p.getParameter<int>("cachevalue");
0668         produces<unsigned int>();
0669         produces<unsigned int, edm::Transition::BeginRun>("a");
0670       }
0671 
0672       static std::shared_ptr<bool> globalBeginRun(edm::Run const& iRun, edm::EventSetup const&, GlobalCache const*) {
0673         gbr = true;
0674         ger = false;
0675         gbrp = false;
0676         return std::shared_ptr<bool>{};
0677       }
0678 
0679       void produce(edm::Event&, edm::EventSetup const&) override {
0680         if (!gbrp) {
0681           throw cms::Exception("out of sequence") << "produce before globalBeginRunProduce";
0682         }
0683       }
0684 
0685       static void globalBeginRunProduce(edm::Run& iRun, edm::EventSetup const&, RunContext const*) {
0686         gbrp = true;
0687         ++m_count;
0688         if (!gbr) {
0689           throw cms::Exception("begin out of sequence") << "globalBeginRunProduce seen before globalBeginRun";
0690         }
0691       }
0692 
0693       static void globalEndRun(edm::Run const& iRun, edm::EventSetup const&, RunContext const* iContext) {
0694         if (!gbr) {
0695           throw cms::Exception("end out of sequence") << "globalEndRun seen before globalBeginRun in Run" << iRun.run();
0696         }
0697         gbr = false;
0698         ger = true;
0699       }
0700 
0701       ~TestBeginRunProducer() {
0702         if (m_count != trans_) {
0703           throw cms::Exception("transitions") << m_count << " but it was supposed to be " << trans_;
0704         }
0705       }
0706     };
0707 
0708     class TestEndRunProducer : public edm::stream::EDProducer<edm::RunCache<bool>, edm::EndRunProducer> {
0709     public:
0710       static std::atomic<unsigned int> m_count;
0711       unsigned int trans_;
0712       static std::atomic<unsigned int> cvalue_;
0713       static std::atomic<bool> gbr;
0714       static std::atomic<bool> ger;
0715       static std::atomic<bool> p;
0716 
0717       static std::shared_ptr<bool> globalBeginRun(edm::Run const& iRun, edm::EventSetup const&, GlobalCache const*) {
0718         gbr = true;
0719         ger = false;
0720         p = false;
0721         return std::shared_ptr<bool>{};
0722       }
0723 
0724       TestEndRunProducer(edm::ParameterSet const& p) {
0725         trans_ = p.getParameter<int>("transitions");
0726         cvalue_ = p.getParameter<int>("cachevalue");
0727         produces<unsigned int>();
0728         produces<unsigned int, edm::Transition::EndRun>("a");
0729       }
0730 
0731       void produce(edm::Event&, edm::EventSetup const&) override { p = true; }
0732 
0733       static void globalEndRunProduce(edm::Run& iRun, edm::EventSetup const&, RunContext const*) {
0734         ++m_count;
0735         if (!p) {
0736           throw cms::Exception("out of sequence") << "globalEndRunProduce seen before produce";
0737         }
0738         if (ger) {
0739           throw cms::Exception("out of sequence") << "globalEndRun seen before globalEndRunProduce";
0740         }
0741       }
0742 
0743       static void globalEndRun(edm::Run const& iRun, edm::EventSetup const&, RunContext const* iContext) {
0744         if (!gbr) {
0745           throw cms::Exception("out of sequence") << "globalEndRun seen before globalBeginRun in Run" << iRun.run();
0746         }
0747         gbr = false;
0748         ger = true;
0749       }
0750 
0751       ~TestEndRunProducer() {
0752         if (m_count != trans_) {
0753           throw cms::Exception("transitions") << m_count << " but it was supposed to be " << trans_;
0754         }
0755       }
0756     };
0757 
0758     class TestBeginLumiBlockProducer
0759         : public edm::stream::EDProducer<edm::LuminosityBlockCache<bool>, edm::BeginLuminosityBlockProducer> {
0760     public:
0761       static std::atomic<unsigned int> m_count;
0762       unsigned int trans_;
0763       static std::atomic<unsigned int> cvalue_;
0764       static std::atomic<bool> gbl;
0765       static std::atomic<bool> gel;
0766       static std::atomic<bool> gblp;
0767 
0768       TestBeginLumiBlockProducer(edm::ParameterSet const& p) {
0769         trans_ = p.getParameter<int>("transitions");
0770         cvalue_ = p.getParameter<int>("cachevalue");
0771         produces<unsigned int>();
0772         produces<unsigned int, edm::Transition::BeginLuminosityBlock>("a");
0773       }
0774 
0775       void produce(edm::Event&, edm::EventSetup const&) override {
0776         if (!gblp) {
0777           throw cms::Exception("begin out of sequence") << "produce seen before globalBeginLumiBlockProduce";
0778         }
0779       }
0780 
0781       static void globalBeginLuminosityBlockProduce(edm::LuminosityBlock&,
0782                                                     edm::EventSetup const&,
0783                                                     LuminosityBlockContext const*) {
0784         ++m_count;
0785         if (!gbl) {
0786           throw cms::Exception("begin out of sequence")
0787               << "globalBeginLumiBlockProduce seen before globalBeginLumiBlock";
0788         }
0789         gblp = true;
0790       }
0791 
0792       static std::shared_ptr<bool> globalBeginLuminosityBlock(edm::LuminosityBlock const& iLB,
0793                                                               edm::EventSetup const&,
0794                                                               RunContext const*) {
0795         gbl = true;
0796         gel = false;
0797         gblp = false;
0798         return std::shared_ptr<bool>();
0799       }
0800 
0801       static void globalEndLuminosityBlock(edm::LuminosityBlock const& iLB,
0802                                            edm::EventSetup const&,
0803                                            LuminosityBlockContext const* iLBContext) {
0804         if (!gbl) {
0805           throw cms::Exception("end out of sequence")
0806               << "globalEndLuminosityBlock seen before globalBeginLuminosityBlock in LuminosityBlock"
0807               << iLB.luminosityBlock();
0808         }
0809         gel = true;
0810         gbl = false;
0811       }
0812 
0813       ~TestBeginLumiBlockProducer() {
0814         if (m_count != trans_) {
0815           throw cms::Exception("transitions") << m_count << " but it was supposed to be " << trans_;
0816         }
0817       }
0818     };
0819 
0820     class TestEndLumiBlockProducer
0821         : public edm::stream::EDProducer<edm::LuminosityBlockCache<bool>, edm::EndLuminosityBlockProducer> {
0822     public:
0823       static std::atomic<unsigned int> m_count;
0824       unsigned int trans_;
0825       static std::atomic<unsigned int> cvalue_;
0826       static std::atomic<bool> gbl;
0827       static std::atomic<bool> gel;
0828       static std::atomic<bool> p;
0829 
0830       TestEndLumiBlockProducer(edm::ParameterSet const& p) {
0831         trans_ = p.getParameter<int>("transitions");
0832         cvalue_ = p.getParameter<int>("cachevalue");
0833         produces<unsigned int>();
0834         produces<unsigned int, edm::Transition::EndLuminosityBlock>("a");
0835       }
0836 
0837       void produce(edm::Event&, edm::EventSetup const&) override { p = true; }
0838 
0839       static void globalEndLuminosityBlockProduce(edm::LuminosityBlock&,
0840                                                   edm::EventSetup const&,
0841                                                   LuminosityBlockContext const*) {
0842         ++m_count;
0843         if (!p) {
0844           throw cms::Exception("out of sequence") << "globalEndLumiBlockProduce seen before produce";
0845         }
0846       }
0847 
0848       static std::shared_ptr<bool> globalBeginLuminosityBlock(edm::LuminosityBlock const& iLB,
0849                                                               edm::EventSetup const&,
0850                                                               RunContext const*) {
0851         gbl = true;
0852         gel = false;
0853         p = false;
0854         return std::shared_ptr<bool>{};
0855       }
0856 
0857       static void globalEndLuminosityBlock(edm::LuminosityBlock const& iLB,
0858                                            edm::EventSetup const&,
0859                                            LuminosityBlockContext const* iLBContext) {
0860         if (!gbl) {
0861           throw cms::Exception("end out of sequence")
0862               << "globalEndLuminosityBlock seen before globalBeginLuminosityBlock in LuminosityBlock"
0863               << iLB.luminosityBlock();
0864         }
0865       }
0866 
0867       ~TestEndLumiBlockProducer() {
0868         if (m_count != trans_) {
0869           throw cms::Exception("transitions") << m_count << " but it was supposed to be " << trans_;
0870         }
0871       }
0872     };
0873 
0874     struct Count {
0875       Count() : m_value(0), m_expectedValue(0) {}
0876       //Using mutable since we want to update the value.
0877       mutable std::atomic<unsigned int> m_value;
0878       mutable std::atomic<unsigned int> m_expectedValue;
0879       // Set only in constructor, framework runs constructors serially
0880       CMS_THREAD_SAFE mutable edm::EDPutTokenT<unsigned int> m_putToken;
0881     };
0882 
0883     class TestAccumulator
0884         : public edm::stream::EDProducer<edm::GlobalCache<Count>, edm::Accumulator, edm::EndLuminosityBlockProducer> {
0885     public:
0886       static std::atomic<unsigned int> m_expectedCount;
0887 
0888       explicit TestAccumulator(edm::ParameterSet const& p, Count const* iCount) {
0889         iCount->m_expectedValue = p.getParameter<unsigned int>("expectedCount");
0890         if (iCount->m_putToken.isUninitialized()) {
0891           iCount->m_putToken = produces<unsigned int, edm::Transition::EndLuminosityBlock>();
0892         }
0893       }
0894 
0895       static std::unique_ptr<Count> initializeGlobalCache(edm::ParameterSet const&) {
0896         return std::unique_ptr<Count>(new Count());
0897       }
0898 
0899       void accumulate(edm::Event const&, edm::EventSetup const&) override { ++(globalCache()->m_value); }
0900 
0901       static void globalEndLuminosityBlockProduce(edm::LuminosityBlock& l,
0902                                                   edm::EventSetup const&,
0903                                                   LuminosityBlockContext const* ctx) {
0904         Count const* count = ctx->global();
0905         l.emplace(count->m_putToken, count->m_value.load());
0906       }
0907 
0908       static void globalEndJob(Count const* iCount) {
0909         if (iCount->m_value != iCount->m_expectedValue) {
0910           throw cms::Exception("CountEvents") << "Number of events seen = " << iCount->m_value
0911                                               << " but it was supposed to be " << iCount->m_expectedValue;
0912         }
0913       }
0914 
0915       ~TestAccumulator() {}
0916     };
0917 
0918     class TestInputProcessBlockCache {
0919     public:
0920       long long int value_ = 0;
0921     };
0922 
0923     class TestInputProcessBlockCache1 {
0924     public:
0925       long long int value_ = 0;
0926     };
0927 
0928     class InputProcessBlockIntProducer
0929         : public edm::stream::EDProducer<
0930               edm::InputProcessBlockCache<int, TestInputProcessBlockCache, TestInputProcessBlockCache1>> {
0931     public:
0932       explicit InputProcessBlockIntProducer(edm::ParameterSet const& pset) {
0933         {
0934           expectedByRun_ = pset.getParameter<std::vector<int>>("expectedByRun");
0935           sleepTime_ = pset.getParameter<unsigned int>("sleepTime");
0936           auto tag = pset.getParameter<edm::InputTag>("consumesBeginProcessBlock");
0937           if (not tag.label().empty()) {
0938             getTokenBegin_ = consumes<IntProduct, edm::InProcess>(tag);
0939           }
0940         }
0941         {
0942           auto tag = pset.getParameter<edm::InputTag>("consumesEndProcessBlock");
0943           if (not tag.label().empty()) {
0944             getTokenEnd_ = consumes<IntProduct, edm::InProcess>(tag);
0945           }
0946         }
0947         registerProcessBlockCacheFiller<TestInputProcessBlockCache1>(
0948             getTokenBegin_,
0949             [this](edm::ProcessBlock const& processBlock,
0950                    std::shared_ptr<TestInputProcessBlockCache1> const& previousCache) {
0951               auto returnValue = std::make_shared<TestInputProcessBlockCache1>();
0952               returnValue->value_ += processBlock.get(getTokenBegin_).value;
0953               returnValue->value_ += processBlock.get(getTokenEnd_).value;
0954               return returnValue;
0955             });
0956       }
0957 
0958       static void accessInputProcessBlock(edm::ProcessBlock const&) {
0959         edm::LogAbsolute("InputProcessBlockIntProducer") << "InputProcessBlockIntProducer::accessInputProcessBlock";
0960       }
0961 
0962       void produce(edm::Event& event, edm::EventSetup const&) override {
0963         auto cacheTuple = processBlockCaches(event);
0964         if (!expectedByRun_.empty()) {
0965           if (expectedByRun_.at(event.run() - 1) !=
0966               std::get<edm::CacheHandle<TestInputProcessBlockCache1>>(cacheTuple)->value_) {
0967             throw cms::Exception("UnexpectedValue")
0968                 << "InputProcessBlockIntProducer::produce cached value was "
0969                 << std::get<edm::CacheHandle<TestInputProcessBlockCache1>>(cacheTuple)->value_
0970                 << " but it was supposed to be " << expectedByRun_.at(event.run() - 1);
0971           }
0972         }
0973         // Force events to be processed concurrently
0974         if (sleepTime_ > 0) {
0975           usleep(sleepTime_);
0976         }
0977       }
0978 
0979     private:
0980       edm::EDGetTokenT<IntProduct> getTokenBegin_;
0981       edm::EDGetTokenT<IntProduct> getTokenEnd_;
0982       std::vector<int> expectedByRun_;
0983       unsigned int sleepTime_{0};
0984     };
0985 
0986     struct InputProcessBlockGlobalCacheAn {
0987       // The tokens are duplicated in this test module to prove that they
0988       // work both as GlobalCache members and module data members.
0989       // We need them as GlobalCache members for accessInputProcessBlock.
0990       // In registerProcessBlockCacheFiller we use tokens that are member
0991       // variables of the class and because the lambda captures the "this"
0992       // pointer of the zeroth stream module instance. We always
0993       // use the zeroth EDConsumer. In the case of registerProcessBlockCacheFiller,
0994       // either set of tokens would work. Note that in the GlobalCache case
0995       // there is a slight weirdness that the zeroth consumer is used but
0996       // the token comes from the last consumer instance. It works because
0997       // all the stream module instances have EDConsumer base classes with
0998       // containers with the same contents in the same order (not 100% guaranteed,
0999       // but it would be difficult to implement a module where this isn't true).
1000       CMS_THREAD_SAFE mutable edm::EDGetTokenT<IntProduct> getTokenBegin_;
1001       CMS_THREAD_SAFE mutable edm::EDGetTokenT<IntProduct> getTokenEnd_;
1002       CMS_THREAD_SAFE mutable edm::EDGetTokenT<IntProduct> getTokenBeginM_;
1003       CMS_THREAD_SAFE mutable edm::EDGetTokenT<IntProduct> getTokenEndM_;
1004       mutable std::atomic<unsigned int> transitions_{0};
1005       int sum_{0};
1006       unsigned int expectedTransitions_{0};
1007       std::vector<int> expectedByRun_;
1008       int expectedSum_{0};
1009       unsigned int sleepTime_{0};
1010     };
1011 
1012     // Same thing as previous class except with a GlobalCache added
1013     class InputProcessBlockIntProducerG
1014         : public edm::stream::EDProducer<
1015               edm::InputProcessBlockCache<int, TestInputProcessBlockCache, TestInputProcessBlockCache1>,
1016               edm::GlobalCache<InputProcessBlockGlobalCacheAn>> {
1017     public:
1018       explicit InputProcessBlockIntProducerG(edm::ParameterSet const& pset,
1019                                              InputProcessBlockGlobalCacheAn const* testGlobalCache) {
1020         {
1021           auto tag = pset.getParameter<edm::InputTag>("consumesBeginProcessBlock");
1022           if (not tag.label().empty()) {
1023             getTokenBegin_ = consumes<IntProduct, edm::InProcess>(tag);
1024             testGlobalCache->getTokenBegin_ = getTokenBegin_;
1025           }
1026         }
1027         {
1028           auto tag = pset.getParameter<edm::InputTag>("consumesEndProcessBlock");
1029           if (not tag.label().empty()) {
1030             getTokenEnd_ = consumes<IntProduct, edm::InProcess>(tag);
1031             testGlobalCache->getTokenEnd_ = getTokenEnd_;
1032           }
1033         }
1034         {
1035           auto tag = pset.getParameter<edm::InputTag>("consumesBeginProcessBlockM");
1036           if (not tag.label().empty()) {
1037             getTokenBeginM_ = consumes<IntProduct, edm::InProcess>(tag);
1038             testGlobalCache->getTokenBeginM_ = getTokenBeginM_;
1039           }
1040         }
1041         {
1042           auto tag = pset.getParameter<edm::InputTag>("consumesEndProcessBlockM");
1043           if (not tag.label().empty()) {
1044             getTokenEndM_ = consumes<IntProduct, edm::InProcess>(tag);
1045             testGlobalCache->getTokenEndM_ = getTokenEndM_;
1046           }
1047         }
1048         registerProcessBlockCacheFiller<int>(
1049             getTokenBegin_, [this](edm::ProcessBlock const& processBlock, std::shared_ptr<int> const& previousCache) {
1050               auto returnValue = std::make_shared<int>(0);
1051               *returnValue += processBlock.get(getTokenBegin_).value;
1052               *returnValue += processBlock.get(getTokenEnd_).value;
1053               ++globalCache()->transitions_;
1054               return returnValue;
1055             });
1056         registerProcessBlockCacheFiller<1>(getTokenBegin_,
1057                                            [this](edm::ProcessBlock const& processBlock,
1058                                                   std::shared_ptr<TestInputProcessBlockCache> const& previousCache) {
1059                                              auto returnValue = std::make_shared<TestInputProcessBlockCache>();
1060                                              returnValue->value_ += processBlock.get(getTokenBegin_).value;
1061                                              returnValue->value_ += processBlock.get(getTokenEnd_).value;
1062                                              ++globalCache()->transitions_;
1063                                              return returnValue;
1064                                            });
1065         registerProcessBlockCacheFiller<TestInputProcessBlockCache1>(
1066             getTokenBegin_,
1067             [this](edm::ProcessBlock const& processBlock,
1068                    std::shared_ptr<TestInputProcessBlockCache1> const& previousCache) {
1069               auto returnValue = std::make_shared<TestInputProcessBlockCache1>();
1070               returnValue->value_ += processBlock.get(getTokenBegin_).value;
1071               returnValue->value_ += processBlock.get(getTokenEnd_).value;
1072               ++globalCache()->transitions_;
1073               return returnValue;
1074             });
1075       }
1076 
1077       static std::unique_ptr<InputProcessBlockGlobalCacheAn> initializeGlobalCache(edm::ParameterSet const& pset) {
1078         auto testGlobalCache = std::make_unique<InputProcessBlockGlobalCacheAn>();
1079         testGlobalCache->expectedTransitions_ = pset.getParameter<int>("transitions");
1080         testGlobalCache->expectedByRun_ = pset.getParameter<std::vector<int>>("expectedByRun");
1081         testGlobalCache->expectedSum_ = pset.getParameter<int>("expectedSum");
1082         testGlobalCache->sleepTime_ = pset.getParameter<unsigned int>("sleepTime");
1083         return testGlobalCache;
1084       }
1085 
1086       static void accessInputProcessBlock(edm::ProcessBlock const& processBlock,
1087                                           InputProcessBlockGlobalCacheAn* testGlobalCache) {
1088         if (processBlock.processName() == "PROD1") {
1089           testGlobalCache->sum_ += processBlock.get(testGlobalCache->getTokenBegin_).value;
1090           testGlobalCache->sum_ += processBlock.get(testGlobalCache->getTokenEnd_).value;
1091         }
1092         if (processBlock.processName() == "MERGE") {
1093           testGlobalCache->sum_ += processBlock.get(testGlobalCache->getTokenBeginM_).value;
1094           testGlobalCache->sum_ += processBlock.get(testGlobalCache->getTokenEndM_).value;
1095         }
1096         ++testGlobalCache->transitions_;
1097       }
1098 
1099       void produce(edm::Event& event, edm::EventSetup const&) override {
1100         auto cacheTuple = processBlockCaches(event);
1101         auto testGlobalCache = globalCache();
1102         if (!testGlobalCache->expectedByRun_.empty()) {
1103           if (testGlobalCache->expectedByRun_.at(event.run() - 1) != *std::get<edm::CacheHandle<int>>(cacheTuple)) {
1104             throw cms::Exception("UnexpectedValue")
1105                 << "InputProcessBlockIntProducerG::produce cached value was "
1106                 << *std::get<edm::CacheHandle<int>>(cacheTuple) << " but it was supposed to be "
1107                 << testGlobalCache->expectedByRun_.at(event.run() - 1);
1108           }
1109           if (testGlobalCache->expectedByRun_.at(event.run() - 1) != std::get<1>(cacheTuple)->value_) {
1110             throw cms::Exception("UnexpectedValue")
1111                 << "InputProcessBlockIntProducerG::produce second cached value was " << std::get<1>(cacheTuple)->value_
1112                 << " but it was supposed to be " << testGlobalCache->expectedByRun_.at(event.run() - 1);
1113           }
1114           if (testGlobalCache->expectedByRun_.at(event.run() - 1) !=
1115               std::get<edm::CacheHandle<TestInputProcessBlockCache1>>(cacheTuple)->value_) {
1116             throw cms::Exception("UnexpectedValue")
1117                 << "InputProcessBlockIntProducerG::produce third cached value was "
1118                 << std::get<edm::CacheHandle<TestInputProcessBlockCache1>>(cacheTuple)->value_
1119                 << " but it was supposed to be " << testGlobalCache->expectedByRun_.at(event.run() - 1);
1120           }
1121         }
1122         ++testGlobalCache->transitions_;
1123 
1124         // Force events to be processed concurrently
1125         if (testGlobalCache->sleepTime_ > 0) {
1126           usleep(testGlobalCache->sleepTime_);
1127         }
1128       }
1129 
1130       static void globalEndJob(InputProcessBlockGlobalCacheAn* testGlobalCache) {
1131         if (testGlobalCache->transitions_ != testGlobalCache->expectedTransitions_) {
1132           throw cms::Exception("transitions")
1133               << "InputProcessBlockIntProducerG transitions " << testGlobalCache->transitions_
1134               << " but it was supposed to be " << testGlobalCache->expectedTransitions_;
1135         }
1136 
1137         if (testGlobalCache->sum_ != testGlobalCache->expectedSum_) {
1138           throw cms::Exception("UnexpectedValue") << "InputProcessBlockIntProducerG sum " << testGlobalCache->sum_
1139                                                   << " but it was supposed to be " << testGlobalCache->expectedSum_;
1140         }
1141       }
1142 
1143     private:
1144       edm::EDGetTokenT<IntProduct> getTokenBegin_;
1145       edm::EDGetTokenT<IntProduct> getTokenEnd_;
1146       edm::EDGetTokenT<IntProduct> getTokenBeginM_;
1147       edm::EDGetTokenT<IntProduct> getTokenEndM_;
1148     };
1149 
1150   }  // namespace stream
1151 }  // namespace edmtest
1152 std::atomic<unsigned int> edmtest::stream::GlobalIntProducer::m_count{0};
1153 std::atomic<unsigned int> edmtest::stream::RunIntProducer::m_count{0};
1154 std::atomic<unsigned int> edmtest::stream::LumiIntProducer::m_count{0};
1155 std::atomic<unsigned int> edmtest::stream::RunSummaryIntProducer::m_count{0};
1156 std::atomic<unsigned int> edmtest::stream::LumiSummaryIntProducer::m_count{0};
1157 std::atomic<unsigned int> edmtest::stream::TestBeginRunProducer::m_count{0};
1158 std::atomic<unsigned int> edmtest::stream::TestEndRunProducer::m_count{0};
1159 std::atomic<unsigned int> edmtest::stream::TestBeginLumiBlockProducer::m_count{0};
1160 std::atomic<unsigned int> edmtest::stream::TestEndLumiBlockProducer::m_count{0};
1161 std::atomic<unsigned int> edmtest::stream::GlobalIntProducer::cvalue_{0};
1162 std::atomic<unsigned int> edmtest::stream::RunIntProducer::cvalue_{0};
1163 std::atomic<unsigned int> edmtest::stream::LumiIntProducer::cvalue_{0};
1164 std::atomic<unsigned int> edmtest::stream::RunSummaryIntProducer::cvalue_{0};
1165 std::atomic<unsigned int> edmtest::stream::LumiSummaryIntProducer::cvalue_{0};
1166 std::atomic<unsigned int> edmtest::stream::TestBeginRunProducer::cvalue_{0};
1167 std::atomic<unsigned int> edmtest::stream::TestEndRunProducer::cvalue_{0};
1168 std::atomic<unsigned int> edmtest::stream::TestBeginLumiBlockProducer::cvalue_{0};
1169 std::atomic<unsigned int> edmtest::stream::TestEndLumiBlockProducer::cvalue_{0};
1170 std::atomic<bool> edmtest::stream::RunSummaryIntProducer::globalBeginRunCalled_{false};
1171 std::atomic<bool> edmtest::stream::LumiSummaryIntProducer::globalBeginLumiCalled_{false};
1172 std::atomic<bool> edmtest::stream::TestBeginRunProducer::gbr{false};
1173 std::atomic<bool> edmtest::stream::TestBeginRunProducer::gbrp{false};
1174 std::atomic<bool> edmtest::stream::TestBeginRunProducer::ger{false};
1175 std::atomic<bool> edmtest::stream::TestEndRunProducer::gbr{false};
1176 std::atomic<bool> edmtest::stream::TestEndRunProducer::ger{false};
1177 std::atomic<bool> edmtest::stream::TestEndRunProducer::p{false};
1178 std::atomic<bool> edmtest::stream::TestBeginLumiBlockProducer::gbl{false};
1179 std::atomic<bool> edmtest::stream::TestBeginLumiBlockProducer::gblp{false};
1180 std::atomic<bool> edmtest::stream::TestBeginLumiBlockProducer::gel{false};
1181 std::atomic<bool> edmtest::stream::TestEndLumiBlockProducer::gbl{false};
1182 std::atomic<bool> edmtest::stream::TestEndLumiBlockProducer::gel{false};
1183 std::atomic<bool> edmtest::stream::TestEndLumiBlockProducer::p{false};
1184 DEFINE_FWK_MODULE(edmtest::stream::GlobalIntProducer);
1185 DEFINE_FWK_MODULE(edmtest::stream::RunIntProducer);
1186 DEFINE_FWK_MODULE(edmtest::stream::LumiIntProducer);
1187 DEFINE_FWK_MODULE(edmtest::stream::RunSummaryIntProducer);
1188 DEFINE_FWK_MODULE(edmtest::stream::LumiSummaryIntProducer);
1189 DEFINE_FWK_MODULE(edmtest::stream::ProcessBlockIntProducer);
1190 DEFINE_FWK_MODULE(edmtest::stream::TestBeginProcessBlockProducer);
1191 DEFINE_FWK_MODULE(edmtest::stream::TestEndProcessBlockProducer);
1192 DEFINE_FWK_MODULE(edmtest::stream::ProcessBlockIntProducerNoGlobalCache);
1193 DEFINE_FWK_MODULE(edmtest::stream::TestBeginProcessBlockProducerNoGlobalCache);
1194 DEFINE_FWK_MODULE(edmtest::stream::TestEndProcessBlockProducerNoGlobalCache);
1195 DEFINE_FWK_MODULE(edmtest::stream::TestBeginRunProducer);
1196 DEFINE_FWK_MODULE(edmtest::stream::TestEndRunProducer);
1197 DEFINE_FWK_MODULE(edmtest::stream::TestBeginLumiBlockProducer);
1198 DEFINE_FWK_MODULE(edmtest::stream::TestEndLumiBlockProducer);
1199 DEFINE_FWK_MODULE(edmtest::stream::TestAccumulator);
1200 DEFINE_FWK_MODULE(edmtest::stream::InputProcessBlockIntProducer);
1201 DEFINE_FWK_MODULE(edmtest::stream::InputProcessBlockIntProducerG);