Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-12-10 23:21:46

0001 // -*- C++ -*-
0002 //
0003 // Package:     Framework
0004 // Class  :     EventSetupsController
0005 //
0006 // Implementation:
0007 //     [Notes on implementation]
0008 //
0009 // Original Author:  Chris Jones, W. David Dagenhart
0010 //         Created:  Wed Jan 12 14:30:44 CST 2011
0011 //
0012 
0013 #include "FWCore/Framework/interface/EventSetupsController.h"
0014 
0015 #include "FWCore/Concurrency/interface/SerialTaskQueue.h"
0016 #include "FWCore/Concurrency/interface/WaitingTaskHolder.h"
0017 #include "FWCore/Concurrency/interface/WaitingTaskList.h"
0018 #include "FWCore/Concurrency/interface/FinalWaitingTask.h"
0019 #include "FWCore/Framework/interface/DataKey.h"
0020 #include "FWCore/Framework/interface/ESProductResolver.h"
0021 #include "FWCore/Framework/src/EventSetupProviderMaker.h"
0022 #include "FWCore/Framework/interface/EventSetupProvider.h"
0023 #include "FWCore/Framework/interface/EventSetupRecordKey.h"
0024 #include "FWCore/Framework/interface/IOVSyncValue.h"
0025 #include "FWCore/Framework/interface/ParameterSetIDHolder.h"
0026 #include "FWCore/Framework/src/SendSourceTerminationSignalIfException.h"
0027 #include "FWCore/ParameterSet/interface/ParameterSet.h"
0028 #include "FWCore/ServiceRegistry/interface/ServiceRegistry.h"
0029 #include "FWCore/ServiceRegistry/interface/ServiceToken.h"
0030 #include "FWCore/Utilities/interface/EDMException.h"
0031 #include "FWCore/Utilities/interface/thread_safety_macros.h"
0032 
0033 #include <algorithm>
0034 #include <exception>
0035 #include <iostream>
0036 #include <set>
0037 
0038 namespace edm {
0039   namespace eventsetup {
0040 
0041     EventSetupsController::EventSetupsController() {}
0042     EventSetupsController::EventSetupsController(ModuleTypeResolverMaker const* resolverMaker)
0043         : typeResolverMaker_(resolverMaker) {}
0044 
0045     void EventSetupsController::endIOVsAsync(edm::WaitingTaskHolder iEndTask) {
0046       for (auto& eventSetupRecordIOVQueue : eventSetupRecordIOVQueues_) {
0047         eventSetupRecordIOVQueue->endIOVAsync(iEndTask);
0048       }
0049     }
0050 
0051     std::shared_ptr<EventSetupProvider> EventSetupsController::makeProvider(ParameterSet& iPSet,
0052                                                                             ActivityRegistry* activityRegistry,
0053                                                                             ParameterSet const* eventSetupPset,
0054                                                                             unsigned int maxConcurrentIOVs,
0055                                                                             bool dumpOptions) {
0056       // Makes an EventSetupProvider
0057       // Also parses the prefer information from ParameterSets and puts
0058       // it in a map that is stored in the EventSetupProvider
0059       std::shared_ptr<EventSetupProvider> returnValue(
0060           makeEventSetupProvider(iPSet, providers_.size(), activityRegistry));
0061 
0062       // Construct the ESProducers and ESSources
0063       // shared_ptrs to them are temporarily stored in this
0064       // EventSetupsController and in the EventSetupProvider
0065       fillEventSetupProvider(typeResolverMaker_, *this, *returnValue, iPSet);
0066 
0067       numberOfConcurrentIOVs_.readConfigurationParameters(eventSetupPset, maxConcurrentIOVs, dumpOptions);
0068 
0069       providers_.push_back(returnValue);
0070       return returnValue;
0071     }
0072 
0073     void EventSetupsController::finishConfiguration() {
0074       if (mustFinishConfiguration_) {
0075         for (auto& eventSetupProvider : providers_) {
0076           numberOfConcurrentIOVs_.fillRecordsNotAllowingConcurrentIOVs(*eventSetupProvider);
0077         }
0078 
0079         for (auto& eventSetupProvider : providers_) {
0080           eventSetupProvider->finishConfiguration(numberOfConcurrentIOVs_, hasNonconcurrentFinder_);
0081         }
0082 
0083         // When the ESSources and ESProducers were constructed a first pass was
0084         // done which attempts to get component sharing between SubProcesses
0085         // correct, but in this pass only the configuration of the components
0086         // being shared are compared. This is not good enough for ESProducers.
0087         // In the following function, all the other components that contribute
0088         // to the same record and also the records that record depends on are
0089         // also checked. The component sharing is appropriately fixed as necessary.
0090         // (this needs to be done before updateLookup because this can cause new
0091         // ESProducers to be constructed).
0092         checkESProducerSharing();
0093         clearComponents();
0094 
0095         // updateLookup needs to be called after checkESProducerSharing because
0096         // that can cause new ESProducers to be constructed
0097         for (auto& eventSetupProvider : providers_) {
0098           eventSetupProvider->updateLookup();
0099         }
0100 
0101         initializeEventSetupRecordIOVQueues();
0102         numberOfConcurrentIOVs_.clear();
0103         mustFinishConfiguration_ = false;
0104       }
0105     }
0106 
0107     void EventSetupsController::runOrQueueEventSetupForInstanceAsync(
0108         IOVSyncValue const& iSync,
0109         WaitingTaskHolder& taskToStartAfterIOVInit,
0110         WaitingTaskList& endIOVWaitingTasks,
0111         std::vector<std::shared_ptr<const EventSetupImpl>>& eventSetupImpls,
0112         edm::SerialTaskQueue& queueWhichWaitsForIOVsToFinish,
0113         ActivityRegistry* actReg,
0114         ServiceToken const& iToken,
0115         bool iForceCacheClear) {
0116       auto asyncEventSetup =
0117           [this, &endIOVWaitingTasks, &eventSetupImpls, &queueWhichWaitsForIOVsToFinish, actReg, iForceCacheClear](
0118               IOVSyncValue const& iSync, WaitingTaskHolder& task) {
0119             queueWhichWaitsForIOVsToFinish.pause();
0120             CMS_SA_ALLOW try {
0121               if (iForceCacheClear) {
0122                 forceCacheClear();
0123               }
0124               SendSourceTerminationSignalIfException sentry(actReg);
0125               {
0126                 //all EventSetupRecordIntervalFinders are sequentially set to the
0127                 // new SyncValue in the call. The async part is just waiting for
0128                 // the Records to be available which is done after the SyncValue setup.
0129                 actReg->preESSyncIOVSignal_.emit(iSync);
0130                 auto postSignal = [&iSync](ActivityRegistry* actReg) { actReg->postESSyncIOVSignal_.emit(iSync); };
0131                 std::unique_ptr<ActivityRegistry, decltype(postSignal)> guard(actReg, postSignal);
0132                 eventSetupForInstanceAsync(iSync, task, endIOVWaitingTasks, eventSetupImpls);
0133               }
0134               sentry.completedSuccessfully();
0135             } catch (...) {
0136               task.doneWaiting(std::current_exception());
0137             }
0138           };
0139       if (doWeNeedToWaitForIOVsToFinish(iSync) || iForceCacheClear) {
0140         // We get inside this block if there is an EventSetup
0141         // module not able to handle concurrent IOVs (usually an ESSource)
0142         // and the new sync value is outside the current IOV of that module.
0143         // Also at beginRun when forcing caches to clear.
0144         auto group = taskToStartAfterIOVInit.group();
0145         ServiceWeakToken weakToken = iToken;
0146         queueWhichWaitsForIOVsToFinish.push(*group,
0147                                             [iSync, taskToStartAfterIOVInit, asyncEventSetup, weakToken]() mutable {
0148                                               ServiceRegistry::Operate operate(weakToken.lock());
0149                                               asyncEventSetup(iSync, taskToStartAfterIOVInit);
0150                                             });
0151       } else {
0152         asyncEventSetup(iSync, taskToStartAfterIOVInit);
0153       }
0154     }
0155 
0156     void EventSetupsController::eventSetupForInstanceAsync(
0157         IOVSyncValue const& syncValue,
0158         WaitingTaskHolder const& taskToStartAfterIOVInit,
0159         WaitingTaskList& endIOVWaitingTasks,
0160         std::vector<std::shared_ptr<const EventSetupImpl>>& eventSetupImpls) {
0161       finishConfiguration();
0162 
0163       bool newEventSetupImpl = false;
0164       eventSetupImpls.clear();
0165       eventSetupImpls.reserve(providers_.size());
0166 
0167       // Note that unless there are one or more SubProcesses providers_ will only
0168       // contain one element.
0169 
0170       for (auto& eventSetupProvider : providers_) {
0171         eventSetupProvider->setAllValidityIntervals(syncValue);
0172       }
0173 
0174       for (auto& eventSetupRecordIOVQueue : eventSetupRecordIOVQueues_) {
0175         // For a particular record, if the top level process or any SubProcess requires
0176         // starting a new IOV, then we must start a new IOV for all of them. And we
0177         // need to know whether this is needed at this point in time. This is
0178         // recorded in the EventSetupRecordProviders.
0179         eventSetupRecordIOVQueue->setNewIntervalForAnySubProcess();
0180       }
0181 
0182       for (auto& eventSetupProvider : providers_) {
0183         // Decides whether we can reuse the existing EventSetupImpl and if we can
0184         // returns it. If a new one is needed it will create it, although the pointers
0185         // to the EventSetupRecordImpl's will not be set yet in the returned EventSetupImpl
0186         // object.
0187         eventSetupImpls.push_back(eventSetupProvider->eventSetupForInstance(syncValue, newEventSetupImpl));
0188       }
0189 
0190       for (auto& eventSetupRecordIOVQueue : eventSetupRecordIOVQueues_) {
0191         eventSetupRecordIOVQueue->checkForNewIOVs(taskToStartAfterIOVInit, endIOVWaitingTasks, newEventSetupImpl);
0192       }
0193     }
0194 
0195     bool EventSetupsController::doWeNeedToWaitForIOVsToFinish(IOVSyncValue const& syncValue) const {
0196       if (hasNonconcurrentFinder()) {
0197         for (auto& eventSetupProvider : providers_) {
0198           if (eventSetupProvider->doWeNeedToWaitForIOVsToFinish(syncValue)) {
0199             return true;
0200           }
0201         }
0202       }
0203       return false;
0204     }
0205 
0206     void EventSetupsController::forceCacheClear() {
0207       for (auto& eventSetupProvider : providers_) {
0208         eventSetupProvider->forceCacheClear();
0209       }
0210     }
0211 
0212     std::shared_ptr<ESProductResolverProvider> EventSetupsController::getESProducerAndRegisterProcess(
0213         ParameterSet const& pset, unsigned subProcessIndex) {
0214       // Try to find a ESProductResolverProvider with a matching ParameterSet
0215       auto elements = esproducers_.equal_range(pset.id());
0216       for (auto it = elements.first; it != elements.second; ++it) {
0217         // Untracked parameters must also match, do complete comparison if IDs match
0218         if (isTransientEqual(pset, *it->second.pset())) {
0219           // Register processes with an exact match
0220           it->second.subProcessIndexes().push_back(subProcessIndex);
0221           // Return the ESProductResolverProvider
0222           return it->second.provider();
0223         }
0224       }
0225       // Could not find it
0226       return std::shared_ptr<ESProductResolverProvider>();
0227     }
0228 
0229     void EventSetupsController::putESProducer(ParameterSet& pset,
0230                                               std::shared_ptr<ESProductResolverProvider> const& component,
0231                                               unsigned subProcessIndex) {
0232       auto newElement =
0233           esproducers_.insert(std::pair<ParameterSetID, ESProducerInfo>(pset.id(), ESProducerInfo(&pset, component)));
0234       // Register processes with an exact match
0235       newElement->second.subProcessIndexes().push_back(subProcessIndex);
0236     }
0237 
0238     std::shared_ptr<EventSetupRecordIntervalFinder> EventSetupsController::getESSourceAndRegisterProcess(
0239         ParameterSet const& pset, unsigned subProcessIndex) {
0240       // Try to find a EventSetupRecordIntervalFinder with a matching ParameterSet
0241       auto elements = essources_.equal_range(pset.id());
0242       for (auto it = elements.first; it != elements.second; ++it) {
0243         // Untracked parameters must also match, do complete comparison if IDs match
0244         if (isTransientEqual(pset, *it->second.pset())) {
0245           // Register processes with an exact match
0246           it->second.subProcessIndexes().push_back(subProcessIndex);
0247           // Return the EventSetupRecordIntervalFinder
0248           return it->second.finder();
0249         }
0250       }
0251       // Could not find it
0252       return std::shared_ptr<EventSetupRecordIntervalFinder>();
0253     }
0254 
0255     void EventSetupsController::putESSource(ParameterSet const& pset,
0256                                             std::shared_ptr<EventSetupRecordIntervalFinder> const& component,
0257                                             unsigned subProcessIndex) {
0258       auto newElement =
0259           essources_.insert(std::pair<ParameterSetID, ESSourceInfo>(pset.id(), ESSourceInfo(&pset, component)));
0260       // Register processes with an exact match
0261       newElement->second.subProcessIndexes().push_back(subProcessIndex);
0262     }
0263 
0264     void EventSetupsController::clearComponents() {
0265       esproducers_.clear();
0266       essources_.clear();
0267     }
0268 
0269     void EventSetupsController::lookForMatches(ParameterSetID const& psetID,
0270                                                unsigned subProcessIndex,
0271                                                unsigned precedingProcessIndex,
0272                                                bool& firstProcessWithThisPSet,
0273                                                bool& precedingHasMatchingPSet) const {
0274       auto elements = esproducers_.equal_range(psetID);
0275       for (auto it = elements.first; it != elements.second; ++it) {
0276         std::vector<unsigned> const& subProcessIndexes = it->second.subProcessIndexes();
0277 
0278         auto iFound = std::find(subProcessIndexes.begin(), subProcessIndexes.end(), subProcessIndex);
0279         if (iFound == subProcessIndexes.end()) {
0280           continue;
0281         }
0282 
0283         if (iFound == subProcessIndexes.begin()) {
0284           firstProcessWithThisPSet = true;
0285           precedingHasMatchingPSet = false;
0286         } else {
0287           auto iFoundPreceding = std::find(subProcessIndexes.begin(), iFound, precedingProcessIndex);
0288           if (iFoundPreceding == iFound) {
0289             firstProcessWithThisPSet = false;
0290             precedingHasMatchingPSet = false;
0291           } else {
0292             firstProcessWithThisPSet = false;
0293             precedingHasMatchingPSet = true;
0294           }
0295         }
0296         return;
0297       }
0298       throw edm::Exception(edm::errors::LogicError) << "EventSetupsController::lookForMatches\n"
0299                                                     << "Subprocess index not found. This should never happen\n"
0300                                                     << "Please report this to a Framework Developer\n";
0301     }
0302 
0303     bool EventSetupsController::isFirstMatch(ParameterSetID const& psetID,
0304                                              unsigned subProcessIndex,
0305                                              unsigned precedingProcessIndex) const {
0306       auto elements = esproducers_.equal_range(psetID);
0307       for (auto it = elements.first; it != elements.second; ++it) {
0308         std::vector<unsigned> const& subProcessIndexes = it->second.subProcessIndexes();
0309 
0310         auto iFound = std::find(subProcessIndexes.begin(), subProcessIndexes.end(), subProcessIndex);
0311         if (iFound == subProcessIndexes.end()) {
0312           continue;
0313         }
0314 
0315         auto iFoundPreceding = std::find(subProcessIndexes.begin(), iFound, precedingProcessIndex);
0316         if (iFoundPreceding == iFound) {
0317           break;
0318         } else {
0319           return iFoundPreceding == subProcessIndexes.begin();
0320         }
0321       }
0322       throw edm::Exception(edm::errors::LogicError) << "EventSetupsController::isFirstMatch\n"
0323                                                     << "Subprocess index not found. This should never happen\n"
0324                                                     << "Please report this to a Framework Developer\n";
0325       return false;
0326     }
0327 
0328     bool EventSetupsController::isLastMatch(ParameterSetID const& psetID,
0329                                             unsigned subProcessIndex,
0330                                             unsigned precedingProcessIndex) const {
0331       auto elements = esproducers_.equal_range(psetID);
0332       for (auto it = elements.first; it != elements.second; ++it) {
0333         std::vector<unsigned> const& subProcessIndexes = it->second.subProcessIndexes();
0334 
0335         auto iFound = std::find(subProcessIndexes.begin(), subProcessIndexes.end(), subProcessIndex);
0336         if (iFound == subProcessIndexes.end()) {
0337           continue;
0338         }
0339 
0340         auto iFoundPreceding = std::find(subProcessIndexes.begin(), iFound, precedingProcessIndex);
0341         if (iFoundPreceding == iFound) {
0342           break;
0343         } else {
0344           return (++iFoundPreceding) == iFound;
0345         }
0346       }
0347       throw edm::Exception(edm::errors::LogicError) << "EventSetupsController::isLastMatch\n"
0348                                                     << "Subprocess index not found. This should never happen\n"
0349                                                     << "Please report this to a Framework Developer\n";
0350       return false;
0351     }
0352 
0353     bool EventSetupsController::isMatchingESSource(ParameterSetID const& psetID,
0354                                                    unsigned subProcessIndex,
0355                                                    unsigned precedingProcessIndex) const {
0356       auto elements = essources_.equal_range(psetID);
0357       for (auto it = elements.first; it != elements.second; ++it) {
0358         std::vector<unsigned> const& subProcessIndexes = it->second.subProcessIndexes();
0359 
0360         auto iFound = std::find(subProcessIndexes.begin(), subProcessIndexes.end(), subProcessIndex);
0361         if (iFound == subProcessIndexes.end()) {
0362           continue;
0363         }
0364 
0365         auto iFoundPreceding = std::find(subProcessIndexes.begin(), iFound, precedingProcessIndex);
0366         if (iFoundPreceding == iFound) {
0367           return false;
0368         } else {
0369           return true;
0370         }
0371       }
0372       throw edm::Exception(edm::errors::LogicError) << "EventSetupsController::lookForMatchingESSource\n"
0373                                                     << "Subprocess index not found. This should never happen\n"
0374                                                     << "Please report this to a Framework Developer\n";
0375       return false;
0376     }
0377 
0378     bool EventSetupsController::isMatchingESProducer(ParameterSetID const& psetID,
0379                                                      unsigned subProcessIndex,
0380                                                      unsigned precedingProcessIndex) const {
0381       auto elements = esproducers_.equal_range(psetID);
0382       for (auto it = elements.first; it != elements.second; ++it) {
0383         std::vector<unsigned> const& subProcessIndexes = it->second.subProcessIndexes();
0384 
0385         auto iFound = std::find(subProcessIndexes.begin(), subProcessIndexes.end(), subProcessIndex);
0386         if (iFound == subProcessIndexes.end()) {
0387           continue;
0388         }
0389 
0390         auto iFoundPreceding = std::find(subProcessIndexes.begin(), iFound, precedingProcessIndex);
0391         if (iFoundPreceding == iFound) {
0392           return false;
0393         } else {
0394           return true;
0395         }
0396       }
0397       throw edm::Exception(edm::errors::LogicError) << "EventSetupsController::lookForMatchingESSource\n"
0398                                                     << "Subprocess index not found. This should never happen\n"
0399                                                     << "Please report this to a Framework Developer\n";
0400       return false;
0401     }
0402 
0403     ParameterSet& EventSetupsController::getESProducerPSet(ParameterSetID const& psetID, unsigned subProcessIndex) {
0404       auto elements = esproducers_.equal_range(psetID);
0405       for (auto it = elements.first; it != elements.second; ++it) {
0406         std::vector<unsigned> const& subProcessIndexes = it->second.subProcessIndexes();
0407 
0408         auto iFound = std::find(subProcessIndexes.begin(), subProcessIndexes.end(), subProcessIndex);
0409         if (iFound == subProcessIndexes.end()) {
0410           continue;
0411         }
0412         return *it->second.pset();
0413       }
0414       throw edm::Exception(edm::errors::LogicError) << "EventSetupsController::getESProducerPSet\n"
0415                                                     << "Subprocess index not found. This should never happen\n"
0416                                                     << "Please report this to a Framework Developer\n";
0417     }
0418 
0419     void EventSetupsController::checkESProducerSharing() {
0420       // Loop over SubProcesses, skip the top level process.
0421       auto esProvider = providers_.begin();
0422       auto const esProviderEnd = providers_.end();
0423       if (esProvider != esProviderEnd)
0424         ++esProvider;
0425       for (; esProvider != esProviderEnd; ++esProvider) {
0426         // An element is added to this set for each ESProducer
0427         // when we have determined which preceding process
0428         // this process can share that ESProducer with or
0429         // we have determined that it cannot be shared with
0430         // any preceding process.
0431         // Note the earliest possible preceding process
0432         // will be the one selected if there is more than one.
0433         std::set<ParameterSetIDHolder> sharingCheckDone;
0434 
0435         // This will hold an entry for ESProductResolver's that are
0436         // referenced by an EventSetupRecord in this SubProcess.
0437         // But only for ESProductResolver's that are associated with
0438         // an ESProducer (not the ones associated with ESSource's
0439         // or EDLooper's)
0440         std::map<EventSetupRecordKey, std::vector<ComponentDescription const*>> referencedESProducers;
0441 
0442         // For each EventSetupProvider from a SubProcess, loop over the
0443         // EventSetupProviders from the preceding processes (the first
0444         // preceding process will be the top level process and the others
0445         // SubProcess's)
0446         for (auto precedingESProvider = providers_.begin(); precedingESProvider != esProvider; ++precedingESProvider) {
0447           (*esProvider)
0448               ->checkESProducerSharing(
0449                   typeResolverMaker_, **precedingESProvider, sharingCheckDone, referencedESProducers, *this);
0450         }
0451 
0452         (*esProvider)->resetRecordToResolverPointers();
0453       }
0454       for (auto& eventSetupProvider : providers_) {
0455         eventSetupProvider->clearInitializationData();
0456       }
0457     }
0458 
0459     void EventSetupsController::initializeEventSetupRecordIOVQueues() {
0460       std::set<EventSetupRecordKey> keys;
0461       for (auto const& provider : providers_) {
0462         provider->fillKeys(keys);
0463       }
0464 
0465       for (auto const& key : keys) {
0466         eventSetupRecordIOVQueues_.push_back(
0467             std::make_unique<EventSetupRecordIOVQueue>(numberOfConcurrentIOVs_.numberOfConcurrentIOVs(key)));
0468         EventSetupRecordIOVQueue& iovQueue = *eventSetupRecordIOVQueues_.back();
0469         for (auto& provider : providers_) {
0470           EventSetupRecordProvider* recProvider = provider->tryToGetRecordProvider(key);
0471           if (recProvider) {
0472             iovQueue.addRecProvider(recProvider);
0473           }
0474         }
0475       }
0476     }
0477 
0478     void synchronousEventSetupForInstance(IOVSyncValue const& syncValue,
0479                                           oneapi::tbb::task_group& iGroup,
0480                                           eventsetup::EventSetupsController& espController) {
0481       FinalWaitingTask waitUntilIOVInitializationCompletes{iGroup};
0482 
0483       // These do nothing ...
0484       WaitingTaskList dummyWaitingTaskList;
0485       std::vector<std::shared_ptr<const EventSetupImpl>> dummyEventSetupImpls;
0486 
0487       {
0488         WaitingTaskHolder waitingTaskHolder(iGroup, &waitUntilIOVInitializationCompletes);
0489         // Caught exception is propagated via WaitingTaskHolder
0490         CMS_SA_ALLOW try {
0491           // All the real work is done here.
0492           espController.eventSetupForInstanceAsync(
0493               syncValue, waitingTaskHolder, dummyWaitingTaskList, dummyEventSetupImpls);
0494           dummyWaitingTaskList.doneWaiting(std::exception_ptr{});
0495         } catch (...) {
0496           dummyWaitingTaskList.doneWaiting(std::exception_ptr{});
0497           waitingTaskHolder.doneWaiting(std::current_exception());
0498         }
0499       }
0500       waitUntilIOVInitializationCompletes.wait();
0501     }
0502   }  // namespace eventsetup
0503 }  // namespace edm