Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-04-06 12:12:11

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         checkESProducerSharing();
0091         clearComponents();
0092 
0093         initializeEventSetupRecordIOVQueues();
0094         numberOfConcurrentIOVs_.clear();
0095         mustFinishConfiguration_ = false;
0096       }
0097     }
0098 
0099     void EventSetupsController::runOrQueueEventSetupForInstanceAsync(
0100         IOVSyncValue const& iSync,
0101         WaitingTaskHolder& taskToStartAfterIOVInit,
0102         WaitingTaskList& endIOVWaitingTasks,
0103         std::vector<std::shared_ptr<const EventSetupImpl>>& eventSetupImpls,
0104         edm::SerialTaskQueue& queueWhichWaitsForIOVsToFinish,
0105         ActivityRegistry* actReg,
0106         ServiceToken const& iToken,
0107         bool iForceCacheClear) {
0108       auto asyncEventSetup =
0109           [this, &endIOVWaitingTasks, &eventSetupImpls, &queueWhichWaitsForIOVsToFinish, actReg, iForceCacheClear](
0110               IOVSyncValue const& iSync, WaitingTaskHolder& task) {
0111             queueWhichWaitsForIOVsToFinish.pause();
0112             CMS_SA_ALLOW try {
0113               if (iForceCacheClear) {
0114                 forceCacheClear();
0115               }
0116               SendSourceTerminationSignalIfException sentry(actReg);
0117               {
0118                 //all EventSetupRecordIntervalFinders are sequentially set to the
0119                 // new SyncValue in the call. The async part is just waiting for
0120                 // the Records to be available which is done after the SyncValue setup.
0121                 actReg->preESSyncIOVSignal_.emit(iSync);
0122                 auto postSignal = [&iSync](ActivityRegistry* actReg) { actReg->postESSyncIOVSignal_.emit(iSync); };
0123                 std::unique_ptr<ActivityRegistry, decltype(postSignal)> guard(actReg, postSignal);
0124                 eventSetupForInstanceAsync(iSync, task, endIOVWaitingTasks, eventSetupImpls);
0125               }
0126               sentry.completedSuccessfully();
0127             } catch (...) {
0128               task.doneWaiting(std::current_exception());
0129             }
0130           };
0131       if (doWeNeedToWaitForIOVsToFinish(iSync) || iForceCacheClear) {
0132         // We get inside this block if there is an EventSetup
0133         // module not able to handle concurrent IOVs (usually an ESSource)
0134         // and the new sync value is outside the current IOV of that module.
0135         // Also at beginRun when forcing caches to clear.
0136         auto group = taskToStartAfterIOVInit.group();
0137         ServiceWeakToken weakToken = iToken;
0138         queueWhichWaitsForIOVsToFinish.push(*group,
0139                                             [iSync, taskToStartAfterIOVInit, asyncEventSetup, weakToken]() mutable {
0140                                               ServiceRegistry::Operate operate(weakToken.lock());
0141                                               asyncEventSetup(iSync, taskToStartAfterIOVInit);
0142                                             });
0143       } else {
0144         asyncEventSetup(iSync, taskToStartAfterIOVInit);
0145       }
0146     }
0147 
0148     void EventSetupsController::eventSetupForInstanceAsync(
0149         IOVSyncValue const& syncValue,
0150         WaitingTaskHolder const& taskToStartAfterIOVInit,
0151         WaitingTaskList& endIOVWaitingTasks,
0152         std::vector<std::shared_ptr<const EventSetupImpl>>& eventSetupImpls) {
0153       finishConfiguration();
0154 
0155       bool newEventSetupImpl = false;
0156       eventSetupImpls.clear();
0157       eventSetupImpls.reserve(providers_.size());
0158 
0159       // Note that unless there are one or more SubProcesses providers_ will only
0160       // contain one element.
0161 
0162       for (auto& eventSetupProvider : providers_) {
0163         eventSetupProvider->setAllValidityIntervals(syncValue);
0164       }
0165 
0166       for (auto& eventSetupRecordIOVQueue : eventSetupRecordIOVQueues_) {
0167         // For a particular record, if the top level process or any SubProcess requires
0168         // starting a new IOV, then we must start a new IOV for all of them. And we
0169         // need to know whether this is needed at this point in time. This is
0170         // recorded in the EventSetupRecordProviders.
0171         eventSetupRecordIOVQueue->setNewIntervalForAnySubProcess();
0172       }
0173 
0174       for (auto& eventSetupProvider : providers_) {
0175         // Decides whether we can reuse the existing EventSetupImpl and if we can
0176         // returns it. If a new one is needed it will create it, although the pointers
0177         // to the EventSetupRecordImpl's will not be set yet in the returned EventSetupImpl
0178         // object.
0179         eventSetupImpls.push_back(eventSetupProvider->eventSetupForInstance(syncValue, newEventSetupImpl));
0180       }
0181 
0182       for (auto& eventSetupRecordIOVQueue : eventSetupRecordIOVQueues_) {
0183         eventSetupRecordIOVQueue->checkForNewIOVs(taskToStartAfterIOVInit, endIOVWaitingTasks, newEventSetupImpl);
0184       }
0185     }
0186 
0187     bool EventSetupsController::doWeNeedToWaitForIOVsToFinish(IOVSyncValue const& syncValue) const {
0188       if (hasNonconcurrentFinder()) {
0189         for (auto& eventSetupProvider : providers_) {
0190           if (eventSetupProvider->doWeNeedToWaitForIOVsToFinish(syncValue)) {
0191             return true;
0192           }
0193         }
0194       }
0195       return false;
0196     }
0197 
0198     void EventSetupsController::forceCacheClear() {
0199       for (auto& eventSetupProvider : providers_) {
0200         eventSetupProvider->forceCacheClear();
0201       }
0202     }
0203 
0204     std::shared_ptr<ESProductResolverProvider> EventSetupsController::getESProducerAndRegisterProcess(
0205         ParameterSet const& pset, unsigned subProcessIndex) {
0206       // Try to find a ESProductResolverProvider with a matching ParameterSet
0207       auto elements = esproducers_.equal_range(pset.id());
0208       for (auto it = elements.first; it != elements.second; ++it) {
0209         // Untracked parameters must also match, do complete comparison if IDs match
0210         if (isTransientEqual(pset, *it->second.pset())) {
0211           // Register processes with an exact match
0212           it->second.subProcessIndexes().push_back(subProcessIndex);
0213           // Return the ESProductResolverProvider
0214           return it->second.provider();
0215         }
0216       }
0217       // Could not find it
0218       return std::shared_ptr<ESProductResolverProvider>();
0219     }
0220 
0221     void EventSetupsController::putESProducer(ParameterSet& pset,
0222                                               std::shared_ptr<ESProductResolverProvider> const& component,
0223                                               unsigned subProcessIndex) {
0224       auto newElement =
0225           esproducers_.insert(std::pair<ParameterSetID, ESProducerInfo>(pset.id(), ESProducerInfo(&pset, component)));
0226       // Register processes with an exact match
0227       newElement->second.subProcessIndexes().push_back(subProcessIndex);
0228     }
0229 
0230     std::shared_ptr<EventSetupRecordIntervalFinder> EventSetupsController::getESSourceAndRegisterProcess(
0231         ParameterSet const& pset, unsigned subProcessIndex) {
0232       // Try to find a EventSetupRecordIntervalFinder with a matching ParameterSet
0233       auto elements = essources_.equal_range(pset.id());
0234       for (auto it = elements.first; it != elements.second; ++it) {
0235         // Untracked parameters must also match, do complete comparison if IDs match
0236         if (isTransientEqual(pset, *it->second.pset())) {
0237           // Register processes with an exact match
0238           it->second.subProcessIndexes().push_back(subProcessIndex);
0239           // Return the EventSetupRecordIntervalFinder
0240           return it->second.finder();
0241         }
0242       }
0243       // Could not find it
0244       return std::shared_ptr<EventSetupRecordIntervalFinder>();
0245     }
0246 
0247     void EventSetupsController::putESSource(ParameterSet const& pset,
0248                                             std::shared_ptr<EventSetupRecordIntervalFinder> const& component,
0249                                             unsigned subProcessIndex) {
0250       auto newElement =
0251           essources_.insert(std::pair<ParameterSetID, ESSourceInfo>(pset.id(), ESSourceInfo(&pset, component)));
0252       // Register processes with an exact match
0253       newElement->second.subProcessIndexes().push_back(subProcessIndex);
0254     }
0255 
0256     void EventSetupsController::clearComponents() {
0257       esproducers_.clear();
0258       essources_.clear();
0259     }
0260 
0261     void EventSetupsController::lookForMatches(ParameterSetID const& psetID,
0262                                                unsigned subProcessIndex,
0263                                                unsigned precedingProcessIndex,
0264                                                bool& firstProcessWithThisPSet,
0265                                                bool& precedingHasMatchingPSet) const {
0266       auto elements = esproducers_.equal_range(psetID);
0267       for (auto it = elements.first; it != elements.second; ++it) {
0268         std::vector<unsigned> const& subProcessIndexes = it->second.subProcessIndexes();
0269 
0270         auto iFound = std::find(subProcessIndexes.begin(), subProcessIndexes.end(), subProcessIndex);
0271         if (iFound == subProcessIndexes.end()) {
0272           continue;
0273         }
0274 
0275         if (iFound == subProcessIndexes.begin()) {
0276           firstProcessWithThisPSet = true;
0277           precedingHasMatchingPSet = false;
0278         } else {
0279           auto iFoundPreceding = std::find(subProcessIndexes.begin(), iFound, precedingProcessIndex);
0280           if (iFoundPreceding == iFound) {
0281             firstProcessWithThisPSet = false;
0282             precedingHasMatchingPSet = false;
0283           } else {
0284             firstProcessWithThisPSet = false;
0285             precedingHasMatchingPSet = true;
0286           }
0287         }
0288         return;
0289       }
0290       throw edm::Exception(edm::errors::LogicError) << "EventSetupsController::lookForMatches\n"
0291                                                     << "Subprocess index not found. This should never happen\n"
0292                                                     << "Please report this to a Framework Developer\n";
0293     }
0294 
0295     bool EventSetupsController::isFirstMatch(ParameterSetID const& psetID,
0296                                              unsigned subProcessIndex,
0297                                              unsigned precedingProcessIndex) const {
0298       auto elements = esproducers_.equal_range(psetID);
0299       for (auto it = elements.first; it != elements.second; ++it) {
0300         std::vector<unsigned> const& subProcessIndexes = it->second.subProcessIndexes();
0301 
0302         auto iFound = std::find(subProcessIndexes.begin(), subProcessIndexes.end(), subProcessIndex);
0303         if (iFound == subProcessIndexes.end()) {
0304           continue;
0305         }
0306 
0307         auto iFoundPreceding = std::find(subProcessIndexes.begin(), iFound, precedingProcessIndex);
0308         if (iFoundPreceding == iFound) {
0309           break;
0310         } else {
0311           return iFoundPreceding == subProcessIndexes.begin();
0312         }
0313       }
0314       throw edm::Exception(edm::errors::LogicError) << "EventSetupsController::isFirstMatch\n"
0315                                                     << "Subprocess index not found. This should never happen\n"
0316                                                     << "Please report this to a Framework Developer\n";
0317       return false;
0318     }
0319 
0320     bool EventSetupsController::isLastMatch(ParameterSetID const& psetID,
0321                                             unsigned subProcessIndex,
0322                                             unsigned precedingProcessIndex) const {
0323       auto elements = esproducers_.equal_range(psetID);
0324       for (auto it = elements.first; it != elements.second; ++it) {
0325         std::vector<unsigned> const& subProcessIndexes = it->second.subProcessIndexes();
0326 
0327         auto iFound = std::find(subProcessIndexes.begin(), subProcessIndexes.end(), subProcessIndex);
0328         if (iFound == subProcessIndexes.end()) {
0329           continue;
0330         }
0331 
0332         auto iFoundPreceding = std::find(subProcessIndexes.begin(), iFound, precedingProcessIndex);
0333         if (iFoundPreceding == iFound) {
0334           break;
0335         } else {
0336           return (++iFoundPreceding) == iFound;
0337         }
0338       }
0339       throw edm::Exception(edm::errors::LogicError) << "EventSetupsController::isLastMatch\n"
0340                                                     << "Subprocess index not found. This should never happen\n"
0341                                                     << "Please report this to a Framework Developer\n";
0342       return false;
0343     }
0344 
0345     bool EventSetupsController::isMatchingESSource(ParameterSetID const& psetID,
0346                                                    unsigned subProcessIndex,
0347                                                    unsigned precedingProcessIndex) const {
0348       auto elements = essources_.equal_range(psetID);
0349       for (auto it = elements.first; it != elements.second; ++it) {
0350         std::vector<unsigned> const& subProcessIndexes = it->second.subProcessIndexes();
0351 
0352         auto iFound = std::find(subProcessIndexes.begin(), subProcessIndexes.end(), subProcessIndex);
0353         if (iFound == subProcessIndexes.end()) {
0354           continue;
0355         }
0356 
0357         auto iFoundPreceding = std::find(subProcessIndexes.begin(), iFound, precedingProcessIndex);
0358         if (iFoundPreceding == iFound) {
0359           return false;
0360         } else {
0361           return true;
0362         }
0363       }
0364       throw edm::Exception(edm::errors::LogicError) << "EventSetupsController::lookForMatchingESSource\n"
0365                                                     << "Subprocess index not found. This should never happen\n"
0366                                                     << "Please report this to a Framework Developer\n";
0367       return false;
0368     }
0369 
0370     bool EventSetupsController::isMatchingESProducer(ParameterSetID const& psetID,
0371                                                      unsigned subProcessIndex,
0372                                                      unsigned precedingProcessIndex) const {
0373       auto elements = esproducers_.equal_range(psetID);
0374       for (auto it = elements.first; it != elements.second; ++it) {
0375         std::vector<unsigned> const& subProcessIndexes = it->second.subProcessIndexes();
0376 
0377         auto iFound = std::find(subProcessIndexes.begin(), subProcessIndexes.end(), subProcessIndex);
0378         if (iFound == subProcessIndexes.end()) {
0379           continue;
0380         }
0381 
0382         auto iFoundPreceding = std::find(subProcessIndexes.begin(), iFound, precedingProcessIndex);
0383         if (iFoundPreceding == iFound) {
0384           return false;
0385         } else {
0386           return true;
0387         }
0388       }
0389       throw edm::Exception(edm::errors::LogicError) << "EventSetupsController::lookForMatchingESSource\n"
0390                                                     << "Subprocess index not found. This should never happen\n"
0391                                                     << "Please report this to a Framework Developer\n";
0392       return false;
0393     }
0394 
0395     ParameterSet& EventSetupsController::getESProducerPSet(ParameterSetID const& psetID, unsigned subProcessIndex) {
0396       auto elements = esproducers_.equal_range(psetID);
0397       for (auto it = elements.first; it != elements.second; ++it) {
0398         std::vector<unsigned> const& subProcessIndexes = it->second.subProcessIndexes();
0399 
0400         auto iFound = std::find(subProcessIndexes.begin(), subProcessIndexes.end(), subProcessIndex);
0401         if (iFound == subProcessIndexes.end()) {
0402           continue;
0403         }
0404         return *it->second.pset();
0405       }
0406       throw edm::Exception(edm::errors::LogicError) << "EventSetupsController::getESProducerPSet\n"
0407                                                     << "Subprocess index not found. This should never happen\n"
0408                                                     << "Please report this to a Framework Developer\n";
0409     }
0410 
0411     void EventSetupsController::checkESProducerSharing() {
0412       // Loop over SubProcesses, skip the top level process.
0413       auto esProvider = providers_.begin();
0414       auto const esProviderEnd = providers_.end();
0415       if (esProvider != esProviderEnd)
0416         ++esProvider;
0417       for (; esProvider != esProviderEnd; ++esProvider) {
0418         // An element is added to this set for each ESProducer
0419         // when we have determined which preceding process
0420         // this process can share that ESProducer with or
0421         // we have determined that it cannot be shared with
0422         // any preceding process.
0423         // Note the earliest possible preceding process
0424         // will be the one selected if there is more than one.
0425         std::set<ParameterSetIDHolder> sharingCheckDone;
0426 
0427         // This will hold an entry for ESProductResolver's that are
0428         // referenced by an EventSetupRecord in this SubProcess.
0429         // But only for ESProductResolver's that are associated with
0430         // an ESProducer (not the ones associated with ESSource's
0431         // or EDLooper's)
0432         std::map<EventSetupRecordKey, std::vector<ComponentDescription const*>> referencedESProducers;
0433 
0434         // For each EventSetupProvider from a SubProcess, loop over the
0435         // EventSetupProviders from the preceding processes (the first
0436         // preceding process will be the top level process and the others
0437         // SubProcess's)
0438         for (auto precedingESProvider = providers_.begin(); precedingESProvider != esProvider; ++precedingESProvider) {
0439           (*esProvider)
0440               ->checkESProducerSharing(
0441                   typeResolverMaker_, **precedingESProvider, sharingCheckDone, referencedESProducers, *this);
0442         }
0443 
0444         (*esProvider)->resetRecordToResolverPointers();
0445       }
0446       for (auto& eventSetupProvider : providers_) {
0447         eventSetupProvider->clearInitializationData();
0448       }
0449     }
0450 
0451     void EventSetupsController::initializeEventSetupRecordIOVQueues() {
0452       std::set<EventSetupRecordKey> keys;
0453       for (auto const& provider : providers_) {
0454         provider->fillKeys(keys);
0455       }
0456 
0457       for (auto const& key : keys) {
0458         eventSetupRecordIOVQueues_.push_back(
0459             std::make_unique<EventSetupRecordIOVQueue>(numberOfConcurrentIOVs_.numberOfConcurrentIOVs(key)));
0460         EventSetupRecordIOVQueue& iovQueue = *eventSetupRecordIOVQueues_.back();
0461         for (auto& provider : providers_) {
0462           EventSetupRecordProvider* recProvider = provider->tryToGetRecordProvider(key);
0463           if (recProvider) {
0464             iovQueue.addRecProvider(recProvider);
0465           }
0466         }
0467       }
0468     }
0469 
0470     void synchronousEventSetupForInstance(IOVSyncValue const& syncValue,
0471                                           oneapi::tbb::task_group& iGroup,
0472                                           eventsetup::EventSetupsController& espController) {
0473       FinalWaitingTask waitUntilIOVInitializationCompletes{iGroup};
0474 
0475       // These do nothing ...
0476       WaitingTaskList dummyWaitingTaskList;
0477       std::vector<std::shared_ptr<const EventSetupImpl>> dummyEventSetupImpls;
0478 
0479       {
0480         WaitingTaskHolder waitingTaskHolder(iGroup, &waitUntilIOVInitializationCompletes);
0481         // Caught exception is propagated via WaitingTaskHolder
0482         CMS_SA_ALLOW try {
0483           // All the real work is done here.
0484           espController.eventSetupForInstanceAsync(
0485               syncValue, waitingTaskHolder, dummyWaitingTaskList, dummyEventSetupImpls);
0486           dummyWaitingTaskList.doneWaiting(std::exception_ptr{});
0487         } catch (...) {
0488           dummyWaitingTaskList.doneWaiting(std::exception_ptr{});
0489           waitingTaskHolder.doneWaiting(std::current_exception());
0490         }
0491       }
0492       waitUntilIOVInitializationCompletes.wait();
0493     }
0494   }  // namespace eventsetup
0495 }  // namespace edm