CMS 3D CMS Logo

/afs/cern.ch/work/a/aaltunda/public/www/CMSSW_6_2_7/src/FWCore/Framework/src/Schedule.cc

Go to the documentation of this file.
00001 #include "FWCore/Framework/interface/Schedule.h"
00002 
00003 #include "DataFormats/Provenance/interface/BranchIDListHelper.h"
00004 #include "DataFormats/Provenance/interface/ProcessConfiguration.h"
00005 #include "DataFormats/Provenance/interface/ProductRegistry.h"
00006 #include "FWCore/Framework/interface/EDProducer.h"
00007 #include "FWCore/Framework/interface/OutputModuleDescription.h"
00008 #include "FWCore/Framework/interface/TriggerNamesService.h"
00009 #include "FWCore/Framework/interface/TriggerReport.h"
00010 #include "FWCore/Framework/src/Factory.h"
00011 #include "FWCore/Framework/interface/OutputModule.h"
00012 #include "FWCore/Framework/src/OutputWorker.h"
00013 #include "FWCore/Framework/src/TriggerResultInserter.h"
00014 #include "FWCore/Framework/src/WorkerInPath.h"
00015 #include "FWCore/Framework/src/WorkerMaker.h"
00016 #include "FWCore/Framework/src/WorkerT.h"
00017 #include "FWCore/MessageLogger/interface/MessageLogger.h"
00018 #include "FWCore/ParameterSet/interface/FillProductRegistryTransients.h"
00019 #include "FWCore/ParameterSet/interface/ParameterSet.h"
00020 #include "FWCore/ParameterSet/interface/ParameterSetDescription.h"
00021 #include "FWCore/ParameterSet/interface/Registry.h"
00022 #include "FWCore/Utilities/interface/Algorithms.h"
00023 #include "FWCore/Utilities/interface/ConvertException.h"
00024 #include "FWCore/Utilities/interface/ExceptionCollector.h"
00025 #include "FWCore/Utilities/interface/DictionaryTools.h"
00026 
00027 #include "boost/bind.hpp"
00028 #include "boost/ref.hpp"
00029 
00030 #include <algorithm>
00031 #include <cassert>
00032 #include <cstdlib>
00033 #include <functional>
00034 #include <iomanip>
00035 #include <list>
00036 #include <map>
00037 #include <exception>
00038 
00039 namespace edm {
00040   namespace {
00041 
00042     // Function template to transform each element in the input range to
00043     // a value placed into the output range. The supplied function
00044     // should take a const_reference to the 'input', and write to a
00045     // reference to the 'output'.
00046     template <typename InputIterator, typename ForwardIterator, typename Func>
00047     void
00048     transform_into(InputIterator begin, InputIterator end,
00049                    ForwardIterator out, Func func) {
00050       for (; begin != end; ++begin, ++out) func(*begin, *out);
00051     }
00052 
00053     // Function template that takes a sequence 'from', a sequence
00054     // 'to', and a callable object 'func'. It and applies
00055     // transform_into to fill the 'to' sequence with the values
00056     // calcuated by the callable object, taking care to fill the
00057     // outupt only if all calls succeed.
00058     template <typename FROM, typename TO, typename FUNC>
00059     void
00060     fill_summary(FROM const& from, TO& to, FUNC func) {
00061       TO temp(from.size());
00062       transform_into(from.begin(), from.end(), temp.begin(), func);
00063       to.swap(temp);
00064     }
00065 
00066     // -----------------------------
00067 
00068     // Here we make the trigger results inserter directly.  This should
00069     // probably be a utility in the WorkerRegistry or elsewhere.
00070 
00071     Schedule::WorkerPtr
00072     makeInserter(ParameterSet& proc_pset,
00073                  ProductRegistry& preg,
00074                  ActionTable const& actions,
00075                  boost::shared_ptr<ActivityRegistry> areg,
00076                  boost::shared_ptr<ProcessConfiguration> processConfiguration,
00077                  Schedule::TrigResPtr trptr) {
00078 
00079       ParameterSet* trig_pset = proc_pset.getPSetForUpdate("@trigger_paths");
00080       trig_pset->registerIt();
00081 
00082       WorkerParams work_args(proc_pset, trig_pset, preg, processConfiguration, actions);
00083       ModuleDescription md(trig_pset->id(),
00084                            "TriggerResultInserter",
00085                            "TriggerResults",
00086                            processConfiguration.get());
00087 
00088       areg->preModuleConstructionSignal_(md);
00089       std::unique_ptr<EDProducer> producer(new TriggerResultInserter(*trig_pset, trptr));
00090       areg->postModuleConstructionSignal_(md);
00091 
00092       Schedule::WorkerPtr ptr(new WorkerT<EDProducer>(std::move(producer), md, work_args));
00093       ptr->setActivityRegistry(areg);
00094       return ptr;
00095     }
00096 
00097     bool binary_search_string(std::vector<std::string> const& v, std::string const& s) {
00098       return std::binary_search(v.begin(), v.end(), s);
00099     }
00100     
00101     void
00102     initializeBranchToReadingWorker(ParameterSet const& opts,
00103                                     ProductRegistry const& preg,
00104                                     std::multimap<std::string,Worker*>& branchToReadingWorker)
00105     {
00106       // See if any data has been marked to be deleted early (removing any duplicates)
00107       auto vBranchesToDeleteEarly = opts.getUntrackedParameter<std::vector<std::string>>("canDeleteEarly",std::vector<std::string>());
00108       if(not vBranchesToDeleteEarly.empty()) {
00109         std::sort(vBranchesToDeleteEarly.begin(),vBranchesToDeleteEarly.end(),std::less<std::string>());
00110         vBranchesToDeleteEarly.erase(std::unique(vBranchesToDeleteEarly.begin(),vBranchesToDeleteEarly.end()),
00111                                      vBranchesToDeleteEarly.end());
00112         
00113         // Are the requested items in the product registry?
00114         auto allBranchNames = preg.allBranchNames();
00115         //the branch names all end with a period, which we do not want to compare with
00116         for(auto & b:allBranchNames) {
00117           b.resize(b.size()-1);
00118         }
00119         std::sort(allBranchNames.begin(),allBranchNames.end(),std::less<std::string>());
00120         std::vector<std::string> temp;
00121         temp.reserve(vBranchesToDeleteEarly.size());  
00122         
00123         std::set_intersection(vBranchesToDeleteEarly.begin(),vBranchesToDeleteEarly.end(),
00124                               allBranchNames.begin(),allBranchNames.end(),
00125                               std::back_inserter(temp));
00126         vBranchesToDeleteEarly.swap(temp);
00127         if(temp.size() != vBranchesToDeleteEarly.size()) {
00128           std::vector<std::string> missingProducts;
00129           std::set_difference(temp.begin(),temp.end(),
00130                               vBranchesToDeleteEarly.begin(),vBranchesToDeleteEarly.end(),
00131                               std::back_inserter(missingProducts));
00132           LogInfo l("MissingProductsForCanDeleteEarly");
00133           l<<"The following products in the 'canDeleteEarly' list are not available in this job and will be ignored.";
00134           for(auto const& n:missingProducts){
00135             l<<"\n "<<n;
00136           }
00137         }
00138         //set placeholder for the branch, we will remove the nullptr if a
00139         // module actually wants the branch.
00140         for(auto const& branch:vBranchesToDeleteEarly) {
00141           branchToReadingWorker.insert(std::make_pair(branch, static_cast<Worker*>(nullptr)));
00142         }
00143       }
00144     }
00145 
00146     void
00147     checkAndInsertAlias(std::string const& friendlyClassName,
00148                         std::string const& moduleLabel,
00149                         std::string const& productInstanceName,
00150                         std::string const& processName,
00151                         std::string const& alias,
00152                         std::string const& instanceAlias,
00153                         ProductRegistry const& preg,
00154                         std::multimap<BranchKey, BranchKey>& aliasMap,
00155                         std::map<BranchKey, BranchKey>& aliasKeys) {
00156       std::string const star("*");
00157 
00158       BranchKey key(friendlyClassName, moduleLabel, productInstanceName, processName);
00159       if(preg.productList().find(key) == preg.productList().end()) {
00160         // No product was found matching the alias.
00161         // We throw an exception only if a module with the specified module label was created in this process.
00162         for(auto const& product : preg.productList()) {
00163           if(moduleLabel == product.first.moduleLabel_ && processName == product.first.processName_) {
00164             throw Exception(errors::Configuration, "EDAlias does not match data\n")
00165               << "There are no products of type '" << friendlyClassName << "'\n"
00166               << "with module label '" << moduleLabel << "' and instance name '" << productInstanceName << "'.\n";
00167           }
00168         }
00169       }
00170 
00171       std::string const& theInstanceAlias(instanceAlias == star ? productInstanceName : instanceAlias);
00172       BranchKey aliasKey(friendlyClassName, alias, theInstanceAlias, processName);
00173       if(preg.productList().find(aliasKey) != preg.productList().end()) {
00174         throw Exception(errors::Configuration, "EDAlias conflicts with data\n")
00175           << "A product of type '" << friendlyClassName << "'\n"
00176           << "with module label '" << alias << "' and instance name '" << theInstanceAlias << "'\n"
00177           << "already exists.\n";
00178       }
00179       auto iter = aliasKeys.find(aliasKey);
00180       if(iter != aliasKeys.end()) {
00181         // The alias matches a previous one.  If the same alias is used for different product, throw. 
00182         if(iter->second != key) {
00183           throw Exception(errors::Configuration, "EDAlias conflict\n")
00184             << "The module label alias '" << alias << "' and product instance alias '" << theInstanceAlias << "'\n"
00185             << "are used for multiple products of type '" << friendlyClassName << "'\n"
00186             << "One has module label '" << moduleLabel << "' and product instance name '" << productInstanceName << "',\n"
00187             << "the other has module label '" << iter->second.moduleLabel_ << "' and product instance name '" << iter->second.productInstanceName_ << "'.\n";
00188         }
00189       } else {
00190         auto prodIter = preg.productList().find(key);
00191         if(prodIter != preg.productList().end()) {
00192           if (!prodIter->second.produced()) {
00193             throw Exception(errors::Configuration, "EDAlias\n")
00194               << "The module label alias '" << alias << "' and product instance alias '" << theInstanceAlias << "'\n"
00195               << "are used for a product of type '" << friendlyClassName << "'\n"
00196               << "with module label '" << moduleLabel << "' and product instance name '" << productInstanceName << "',\n"
00197               << "An EDAlias can only be used for products produced in the current process. This one is not.\n";
00198           }
00199           aliasMap.insert(std::make_pair(key, aliasKey));
00200           aliasKeys.insert(std::make_pair(aliasKey, key));
00201         }
00202       }
00203     }
00204 
00205     void
00206     processEDAliases(ParameterSet const& proc_pset, std::string const& processName, ProductRegistry& preg) {
00207       std::vector<std::string> aliases = proc_pset.getParameter<std::vector<std::string> >("@all_aliases");
00208       if(aliases.empty()) {
00209         return;
00210       }
00211       std::string const star("*");
00212       std::string const empty("");
00213       ParameterSetDescription desc;
00214       desc.add<std::string>("type");
00215       desc.add<std::string>("fromProductInstance", star);
00216       desc.add<std::string>("toProductInstance", star);
00217 
00218       std::multimap<BranchKey, BranchKey> aliasMap;
00219 
00220       std::map<BranchKey, BranchKey> aliasKeys; // Used to search for duplicates or clashes.
00221 
00222       // Now, loop over the alias information and store it in aliasMap.
00223       for(std::string const& alias : aliases) {
00224         ParameterSet const& aliasPSet = proc_pset.getParameterSet(alias);
00225         std::vector<std::string> vPSetNames = aliasPSet.getParameterNamesForType<VParameterSet>();
00226         for(std::string const& moduleLabel : vPSetNames) {
00227           VParameterSet vPSet = aliasPSet.getParameter<VParameterSet>(moduleLabel);
00228           for(ParameterSet& pset : vPSet) {
00229             desc.validate(pset);
00230             std::string friendlyClassName = pset.getParameter<std::string>("type"); 
00231             std::string productInstanceName = pset.getParameter<std::string>("fromProductInstance");
00232             std::string instanceAlias = pset.getParameter<std::string>("toProductInstance");
00233             if(productInstanceName == star) {
00234               bool match = false;
00235               BranchKey lowerBound(friendlyClassName, moduleLabel, empty, empty);
00236               for(ProductRegistry::ProductList::const_iterator it = preg.productList().lower_bound(lowerBound);
00237                   it != preg.productList().end() && it->first.friendlyClassName_ == friendlyClassName && it->first.moduleLabel_ == moduleLabel;
00238                   ++it) {
00239                 if(it->first.processName_ != processName) {
00240                   continue;
00241                 }
00242                 match = true;
00243 
00244                 checkAndInsertAlias(friendlyClassName, moduleLabel, it->first.productInstanceName_, processName, alias, instanceAlias, preg, aliasMap, aliasKeys);
00245               }
00246               if(!match) {
00247                 // No product was found matching the alias.
00248                 // We throw an exception only if a module with the specified module label was created in this process.
00249                 for(auto const& product : preg.productList()) {
00250                   if(moduleLabel == product.first.moduleLabel_ && processName == product.first.processName_) {
00251                     throw Exception(errors::Configuration, "EDAlias parameter set mismatch\n")
00252                        << "There are no products of type '" << friendlyClassName << "'\n"
00253                        << "with module label '" << moduleLabel << "'.\n";
00254                   }
00255                 }
00256               }
00257             } else {
00258               checkAndInsertAlias(friendlyClassName, moduleLabel, productInstanceName, processName, alias, instanceAlias, preg, aliasMap, aliasKeys);
00259             }
00260           }
00261         }
00262       }
00263 
00264 
00265       // Now add the new alias entries to the product registry.
00266       for(auto const& aliasEntry : aliasMap) {
00267         ProductRegistry::ProductList::const_iterator it = preg.productList().find(aliasEntry.first);
00268         assert(it != preg.productList().end()); 
00269         preg.addLabelAlias(it->second, aliasEntry.second.moduleLabel_, aliasEntry.second.productInstanceName_);
00270       }
00271 
00272     }
00273   }
00274 
00275   // -----------------------------
00276 
00277   typedef std::vector<std::string> vstring;
00278 
00279   // -----------------------------
00280 
00281   Schedule::Schedule(ParameterSet& proc_pset,
00282                      service::TriggerNamesService& tns,
00283                      ProductRegistry& preg,
00284                      BranchIDListHelper& branchIDListHelper,
00285                      ActionTable const& actions,
00286                      boost::shared_ptr<ActivityRegistry> areg,
00287                      boost::shared_ptr<ProcessConfiguration> processConfiguration,
00288                      const ParameterSet* subProcPSet) :
00289     worker_reg_(areg),
00290     act_table_(&actions),
00291     actReg_(areg),
00292     state_(Ready),
00293     trig_name_list_(tns.getTrigPaths()),
00294     end_path_name_list_(tns.getEndPaths()),
00295     results_(new HLTGlobalStatus(trig_name_list_.size())),
00296     endpath_results_(), // delay!
00297     results_inserter_(),
00298     all_workers_(),
00299     all_output_workers_(),
00300     trig_paths_(),
00301     end_paths_(),
00302     wantSummary_(tns.wantSummary()),
00303     total_events_(),
00304     total_passed_(),
00305     stopwatch_(wantSummary_? new RunStopwatch::StopwatchPointer::element_type : static_cast<RunStopwatch::StopwatchPointer::element_type*> (nullptr)),
00306     unscheduled_(new UnscheduledCallProducer),
00307     endpathsAreActive_(true) {
00308 
00309     ParameterSet const& opts = proc_pset.getUntrackedParameterSet("options", ParameterSet());
00310     bool hasPath = false;
00311 
00312     int trig_bitpos = 0;
00313     vstring labelsOnTriggerPaths;
00314     for (vstring::const_iterator i = trig_name_list_.begin(),
00315            e = trig_name_list_.end();
00316          i != e;
00317          ++i) {
00318       fillTrigPath(proc_pset, preg, processConfiguration, trig_bitpos, *i, results_, &labelsOnTriggerPaths);
00319       ++trig_bitpos;
00320       hasPath = true;
00321     }
00322 
00323     if (hasPath) {
00324       // the results inserter stands alone
00325       results_inserter_ = makeInserter(proc_pset,
00326                                        preg,
00327                                        actions, actReg_, processConfiguration, results_);
00328       addToAllWorkers(results_inserter_.get());
00329     }
00330 
00331     TrigResPtr epptr(new HLTGlobalStatus(end_path_name_list_.size()));
00332     endpath_results_ = epptr;
00333 
00334     // fill normal endpaths
00335     vstring::iterator eib(end_path_name_list_.begin()), eie(end_path_name_list_.end());
00336     for (int bitpos = 0; eib != eie; ++eib, ++bitpos) {
00337       fillEndPath(proc_pset, preg, processConfiguration, bitpos, *eib);
00338     }
00339 
00340     //See if all modules were used
00341     std::set<std::string> usedWorkerLabels;
00342     for (AllWorkers::iterator itWorker = workersBegin();
00343         itWorker != workersEnd();
00344         ++itWorker) {
00345       usedWorkerLabels.insert((*itWorker)->description().moduleLabel());
00346     }
00347     std::vector<std::string> modulesInConfig(proc_pset.getParameter<std::vector<std::string> >("@all_modules"));
00348     std::set<std::string> modulesInConfigSet(modulesInConfig.begin(), modulesInConfig.end());
00349     std::vector<std::string> unusedLabels;
00350     set_difference(modulesInConfigSet.begin(), modulesInConfigSet.end(),
00351                    usedWorkerLabels.begin(), usedWorkerLabels.end(),
00352                    back_inserter(unusedLabels));
00353     //does the configuration say we should allow on demand?
00354     bool allowUnscheduled = opts.getUntrackedParameter<bool>("allowUnscheduled", false);
00355     std::set<std::string> unscheduledLabels;
00356     std::vector<std::string>  shouldBeUsedLabels;
00357     if (!unusedLabels.empty()) {
00358       //Need to
00359       // 1) create worker
00360       // 2) if it is a WorkerT<EDProducer>, add it to our list
00361       // 3) hand list to our delayed reader
00362 
00363       for (std::vector<std::string>::iterator itLabel = unusedLabels.begin(), itLabelEnd = unusedLabels.end();
00364           itLabel != itLabelEnd;
00365           ++itLabel) {
00366         if (allowUnscheduled) {
00367           bool isTracked;
00368           ParameterSet* modulePSet(proc_pset.getPSetForUpdate(*itLabel, isTracked));
00369           assert(isTracked);
00370           assert(modulePSet != 0);
00371           WorkerParams params(proc_pset, modulePSet, preg,
00372                               processConfiguration, *act_table_);
00373           Worker* newWorker(worker_reg_.getWorker(params, *itLabel));
00374           if (newWorker->moduleType() == Worker::kProducer ||
00375               newWorker->moduleType() == Worker::kFilter) {
00376             unscheduledLabels.insert(*itLabel);
00377             unscheduled_->addWorker(newWorker);
00378             //add to list so it gets reset each new event
00379             addToAllWorkers(newWorker);
00380           } else {
00381             //not a producer so should be marked as not used
00382             shouldBeUsedLabels.push_back(*itLabel);
00383           }
00384         } else {
00385           //everthing is marked are unused so no 'on demand' allowed
00386           shouldBeUsedLabels.push_back(*itLabel);
00387         }
00388       }
00389       if (!shouldBeUsedLabels.empty()) {
00390         std::ostringstream unusedStream;
00391         unusedStream << "'" << shouldBeUsedLabels.front() << "'";
00392         for (std::vector<std::string>::iterator itLabel = shouldBeUsedLabels.begin() + 1,
00393               itLabelEnd = shouldBeUsedLabels.end();
00394             itLabel != itLabelEnd;
00395             ++itLabel) {
00396           unusedStream << ",'" << *itLabel << "'";
00397         }
00398         LogInfo("path")
00399           << "The following module labels are not assigned to any path:\n"
00400           << unusedStream.str()
00401           << "\n";
00402       }
00403     }
00404     if (!unscheduledLabels.empty()) {
00405       for (ProductRegistry::ProductList::const_iterator it = preg.productList().begin(),
00406           itEnd = preg.productList().end();
00407           it != itEnd;
00408           ++it) {
00409         if (it->second.produced() &&
00410             it->second.branchType() == InEvent &&
00411             unscheduledLabels.end() != unscheduledLabels.find(it->second.moduleLabel())) {
00412           it->second.setOnDemand();
00413         }
00414       }
00415     }
00416 
00417     std::map<std::string, std::vector<std::pair<std::string, int> > > outputModulePathPositions;
00418     reduceParameterSet(proc_pset, modulesInConfig, modulesInConfigSet, labelsOnTriggerPaths, shouldBeUsedLabels, outputModulePathPositions);
00419 
00420     processEDAliases(proc_pset, processConfiguration->processName(), preg);
00421 
00422     proc_pset.registerIt();
00423     pset::Registry::instance()->extra().setID(proc_pset.id());
00424     processConfiguration->setParameterSetID(proc_pset.id());
00425 
00426     initializeEarlyDelete(opts,preg,subProcPSet);
00427     
00428     // This is used for a little sanity-check to make sure no code
00429     // modifications alter the number of workers at a later date.
00430     size_t all_workers_count = all_workers_.size();
00431 
00432     for (AllWorkers::iterator i = all_workers_.begin(), e = all_workers_.end();
00433          i != e;
00434          ++i) {
00435 
00436       // All the workers should be in all_workers_ by this point. Thus
00437       // we can now fill all_output_workers_.
00438       OutputWorker* ow = dynamic_cast<OutputWorker*>(*i);
00439       if (ow) {
00440         all_output_workers_.push_back(ow);
00441       }
00442     }
00443     // Now that the output workers are filled in, set any output limits or information.
00444     limitOutput(proc_pset, branchIDListHelper.branchIDLists());
00445 
00446     loadMissingDictionaries();
00447 
00448     preg.setFrozen();
00449 
00450     for (AllOutputWorkers::iterator i = all_output_workers_.begin(), e = all_output_workers_.end();
00451          i != e; ++i) {
00452       (*i)->setEventSelectionInfo(outputModulePathPositions, preg.anyProductProduced());
00453       (*i)->selectProducts(preg);
00454     }
00455 
00456     // Sanity check: make sure nobody has added a worker after we've
00457     // already relied on all_workers_ being full.
00458     assert (all_workers_count == all_workers_.size());
00459 
00460     ProcessConfigurationRegistry::instance()->insertMapped(*processConfiguration);
00461     branchIDListHelper.updateRegistries(preg);
00462     fillProductRegistryTransients(*processConfiguration, preg);
00463   } // Schedule::Schedule
00464 
00465   
00466   void Schedule::initializeEarlyDelete(edm::ParameterSet const& opts, edm::ProductRegistry const& preg, 
00467                                        edm::ParameterSet const* subProcPSet) {
00468     //for now, if have a subProcess, don't allow early delete
00469     // In the future we should use the SubProcess's 'keep list' to decide what can be kept
00470     if(subProcPSet)  return;
00471 
00472     //see if 'canDeleteEarly' was set and if so setup the list with those products actually
00473     // registered for this job
00474     std::multimap<std::string,Worker*> branchToReadingWorker;
00475     initializeBranchToReadingWorker(opts,preg,branchToReadingWorker);
00476     
00477     //If no delete early items have been specified we don't have to do anything
00478     if(branchToReadingWorker.size()==0) {
00479       return;
00480     }
00481     const std::vector<std::string> kEmpty;
00482     std::map<Worker*,unsigned int> reserveSizeForWorker;
00483     unsigned int upperLimitOnReadingWorker =0;
00484     unsigned int upperLimitOnIndicies = 0;
00485     unsigned int nUniqueBranchesToDelete=branchToReadingWorker.size();
00486     for (AllWorkers::iterator i = all_workers_.begin(), e = all_workers_.end();
00487          i != e;
00488          ++i) {
00489       OutputWorker* ow = dynamic_cast<OutputWorker*>(*i);
00490       if (ow) {
00491         if(branchToReadingWorker.size()>0) {
00492           //If an OutputModule needs a product, we can't delete it early
00493           // so we should remove it from our list
00494           SelectionsArray const&kept = ow->keptProducts();
00495           for( auto const& item: kept[InEvent]) {
00496             auto found = branchToReadingWorker.equal_range(item->branchName());
00497             if(found.first !=found.second) {
00498               --nUniqueBranchesToDelete;
00499               branchToReadingWorker.erase(found.first,found.second);
00500             }
00501           }
00502         }
00503       } else {
00504         if(branchToReadingWorker.size()>0) {
00505           //determine if this module could read a branch we want to delete early
00506           auto pset = pset::Registry::instance()->getMapped((*i)->description().parameterSetID());
00507           if(0!=pset) {
00508             auto branches = pset->getUntrackedParameter<std::vector<std::string>>("mightGet",kEmpty);
00509             if(not branches.empty()) {
00510               ++upperLimitOnReadingWorker;
00511             }
00512             for(auto const& branch:branches){ 
00513               auto found = branchToReadingWorker.equal_range(branch);
00514               if(found.first != found.second) {
00515                 ++upperLimitOnIndicies;
00516                 ++reserveSizeForWorker[*i];
00517                 if(nullptr == found.first->second) {
00518                   found.first->second = *i;
00519                 } else {
00520                   branchToReadingWorker.insert(make_pair(found.first->first,*i));
00521                 }
00522               }
00523             }
00524           }
00525         }
00526       }
00527     }
00528     {
00529       auto it = branchToReadingWorker.begin();
00530       std::vector<std::string> unusedBranches;
00531       while(it !=branchToReadingWorker.end()) {
00532         if(it->second == nullptr) {
00533           unusedBranches.push_back(it->first);
00534           //erasing the object invalidates the iterator so must advance it first
00535           auto temp = it;
00536           ++it;
00537           branchToReadingWorker.erase(temp);
00538         } else {
00539           ++it;
00540         }
00541       }
00542       if(not unusedBranches.empty()) {
00543         LogWarning l("UnusedProductsForCanDeleteEarly");
00544         l<<"The following products in the 'canDeleteEarly' list are not used in this job and will be ignored.\n"
00545         " If possible, remove the producer from the job or add the product to the producer's own 'mightGet' list.";
00546         for(auto const& n:unusedBranches){
00547           l<<"\n "<<n;
00548         }
00549       }
00550     }  
00551     if(0!=branchToReadingWorker.size()) {
00552       earlyDeleteHelpers_.reserve(upperLimitOnReadingWorker);
00553       earlyDeleteHelperToBranchIndicies_.resize(upperLimitOnIndicies,0);
00554       earlyDeleteBranchToCount_.reserve(nUniqueBranchesToDelete);
00555       std::map<const Worker*,EarlyDeleteHelper*> alreadySeenWorkers;
00556       std::string lastBranchName;
00557       size_t nextOpenIndex = 0;
00558       unsigned int* beginAddress = &(earlyDeleteHelperToBranchIndicies_.front());
00559       for(auto& branchAndWorker:branchToReadingWorker) {
00560         if(lastBranchName != branchAndWorker.first) {
00561           //have to put back the period we removed earlier in order to get the proper name
00562           BranchID bid(branchAndWorker.first+".");
00563           earlyDeleteBranchToCount_.emplace_back(std::make_pair(bid,0U));
00564           lastBranchName = branchAndWorker.first;
00565         }
00566         auto found = alreadySeenWorkers.find(branchAndWorker.second);
00567         if(alreadySeenWorkers.end() == found) {
00568           //NOTE: we will set aside enough space in earlyDeleteHelperToBranchIndicies_ to accommodate
00569           // all the branches that might be read by this worker. However, initially we will only tell the
00570           // EarlyDeleteHelper about the first one. As additional branches are added via 'appendIndex' the
00571           // EarlyDeleteHelper will automatically advance its internal end pointer.
00572           size_t index = nextOpenIndex;
00573           size_t nIndices = reserveSizeForWorker[branchAndWorker.second];
00574           earlyDeleteHelperToBranchIndicies_[index]=earlyDeleteBranchToCount_.size()-1;
00575           earlyDeleteHelpers_.emplace_back(EarlyDeleteHelper(beginAddress+index,
00576                                                              beginAddress+index+1,
00577                                                              &earlyDeleteBranchToCount_));
00578           branchAndWorker.second->setEarlyDeleteHelper(&(earlyDeleteHelpers_.back()));
00579           alreadySeenWorkers.insert(std::make_pair(branchAndWorker.second,&(earlyDeleteHelpers_.back())));
00580           nextOpenIndex +=nIndices;
00581         } else {
00582           found->second->appendIndex(earlyDeleteBranchToCount_.size()-1);
00583         }
00584       }
00585       
00586       //Now we can compactify the earlyDeleteHelperToBranchIndicies_ since we may have over estimated the
00587       // space needed for each module
00588       auto itLast = earlyDeleteHelpers_.begin();
00589       for(auto it = earlyDeleteHelpers_.begin()+1;it != earlyDeleteHelpers_.end();++it) {
00590         if(itLast->end() != it->begin()) {
00591           //figure the offset for next Worker since it hasn't been moved yet so it has the original address
00592           unsigned int delta = it->begin()- itLast->end();
00593           it->shiftIndexPointers(delta);
00594           
00595           earlyDeleteHelperToBranchIndicies_.erase(earlyDeleteHelperToBranchIndicies_.begin()+
00596                                                    (itLast->end()-beginAddress),
00597                                                    earlyDeleteHelperToBranchIndicies_.begin()+
00598                                                    (it->begin()-beginAddress));
00599         }
00600         itLast = it;
00601       }
00602       earlyDeleteHelperToBranchIndicies_.erase(earlyDeleteHelperToBranchIndicies_.begin()+(itLast->end()-beginAddress),
00603                                                earlyDeleteHelperToBranchIndicies_.end());
00604       
00605       //now tell the paths about the deleters
00606       for(auto& p : trig_paths_) {
00607         p.setEarlyDeleteHelpers(alreadySeenWorkers);
00608       }
00609       for(auto& p : end_paths_) {
00610         p.setEarlyDeleteHelpers(alreadySeenWorkers);
00611       }
00612       resetEarlyDelete();
00613     }
00614   }
00615 
00616   void Schedule::reduceParameterSet(ParameterSet& proc_pset,
00617                                     vstring& modulesInConfig,
00618                                     std::set<std::string> const& modulesInConfigSet,
00619                                     vstring& labelsOnTriggerPaths,
00620                                     vstring& shouldBeUsedLabels,
00621                                     std::map<std::string, std::vector<std::pair<std::string, int> > >& outputModulePathPositions) {
00622 
00623     // Before calculating the ParameterSetID of the top level ParameterSet or
00624     // saving it in the registry drop from the top level ParameterSet all
00625     // OutputModules and EDAnalyzers not on trigger paths. If unscheduled
00626     // production is not enabled also drop all the EDFilters and EDProducers
00627     // that are not scheduled. Drop the ParameterSet used to configure the module
00628     // itself. Also drop the other traces of these labels in the top level
00629     // ParameterSet: Remove that labels from @all_modules and from all the
00630     // end paths. If this makes any end paths empty, then remove the end path
00631     // name from @end_paths, and @paths.
00632 
00633     // First make a list of labels to drop
00634     vstring labelsToBeDropped;
00635     vstring outputModuleLabels;
00636     std::string edmType;
00637     std::string const moduleEdmType("@module_edm_type");
00638     std::string const outputModule("OutputModule");
00639     std::string const edAnalyzer("EDAnalyzer");
00640     std::string const edFilter("EDFilter");
00641     std::string const edProducer("EDProducer");
00642     sort_all(labelsOnTriggerPaths);
00643     vstring::const_iterator iLabelsOnTriggerPaths = labelsOnTriggerPaths.begin();
00644     vstring::const_iterator endLabelsOnTriggerPaths = labelsOnTriggerPaths.end();
00645     sort_all(shouldBeUsedLabels);
00646     vstring::const_iterator iShouldBeUsedLabels = shouldBeUsedLabels.begin();
00647     vstring::const_iterator endShouldBeUsedLabels = shouldBeUsedLabels.end();
00648 
00649     for (std::set<std::string>::const_iterator i = modulesInConfigSet.begin(),
00650            e = modulesInConfigSet.end(); i != e; ++i) {
00651       edmType = proc_pset.getParameterSet(*i).getParameter<std::string>(moduleEdmType);
00652       if (edmType == outputModule) {
00653         labelsToBeDropped.push_back(*i);
00654         outputModuleLabels.push_back(*i);
00655       }
00656       else if (edmType == edAnalyzer) {
00657         while (iLabelsOnTriggerPaths != endLabelsOnTriggerPaths &&
00658                *iLabelsOnTriggerPaths < *i) {
00659           ++iLabelsOnTriggerPaths;
00660         }
00661         if (iLabelsOnTriggerPaths == endLabelsOnTriggerPaths ||
00662             *iLabelsOnTriggerPaths != *i) {
00663           labelsToBeDropped.push_back(*i);
00664         }
00665       }
00666       else if (edmType == edFilter || edmType == edProducer) {
00667         while (iShouldBeUsedLabels != endShouldBeUsedLabels &&
00668                *iShouldBeUsedLabels < *i) {
00669           ++iShouldBeUsedLabels;
00670         }
00671         if (iShouldBeUsedLabels != endShouldBeUsedLabels &&
00672             *iShouldBeUsedLabels == *i) {
00673           labelsToBeDropped.push_back(*i);
00674         }
00675       }
00676     }
00677 
00678     // drop the parameter sets used to configure the modules
00679     for_all(labelsToBeDropped, boost::bind(&ParameterSet::eraseOrSetUntrackedParameterSet, boost::ref(proc_pset), _1));
00680 
00681     // drop the labels from @all_modules
00682     vstring::iterator endAfterRemove = std::remove_if(modulesInConfig.begin(), modulesInConfig.end(), boost::bind(binary_search_string, boost::ref(labelsToBeDropped), _1));
00683     modulesInConfig.erase(endAfterRemove, modulesInConfig.end());
00684     proc_pset.addParameter<vstring>(std::string("@all_modules"), modulesInConfig);
00685 
00686     // drop the labels from all end paths
00687     vstring endPathsToBeDropped;
00688     vstring labels;
00689     for (vstring::iterator iEndPath = end_path_name_list_.begin(), endEndPath = end_path_name_list_.end();
00690          iEndPath != endEndPath;
00691          ++iEndPath) {
00692       labels = proc_pset.getParameter<vstring>(*iEndPath);
00693       vstring::iterator iSave = labels.begin();
00694       vstring::iterator iBegin = labels.begin();
00695 
00696       for (vstring::iterator iLabel = labels.begin(), iEnd = labels.end();
00697            iLabel != iEnd; ++iLabel) {
00698         if (binary_search_string(labelsToBeDropped, *iLabel)) {
00699           if (binary_search_string(outputModuleLabels, *iLabel)) {
00700             outputModulePathPositions[*iLabel].emplace_back(*iEndPath, iSave - iBegin);
00701           }
00702         } else {
00703           if (iSave != iLabel) {
00704             iSave->swap(*iLabel);
00705           }
00706           ++iSave;
00707         }
00708       }
00709       labels.erase(iSave, labels.end());
00710       if (labels.empty()) {
00711         // remove empty end paths and save their names
00712         proc_pset.eraseSimpleParameter(*iEndPath);
00713         endPathsToBeDropped.push_back(*iEndPath);
00714       } else {
00715         proc_pset.addParameter<vstring>(*iEndPath, labels);
00716       }
00717     }
00718     sort_all(endPathsToBeDropped);
00719     
00720     // remove empty end paths from @paths
00721     vstring scheduledPaths = proc_pset.getParameter<vstring>("@paths");
00722     endAfterRemove = std::remove_if(scheduledPaths.begin(), scheduledPaths.end(), boost::bind(binary_search_string, boost::ref(endPathsToBeDropped), _1));
00723     scheduledPaths.erase(endAfterRemove, scheduledPaths.end());
00724     proc_pset.addParameter<vstring>(std::string("@paths"), scheduledPaths);
00725 
00726     // remove empty end paths from @end_paths
00727     vstring scheduledEndPaths = proc_pset.getParameter<vstring>("@end_paths");
00728     endAfterRemove = std::remove_if(scheduledEndPaths.begin(), scheduledEndPaths.end(), boost::bind(binary_search_string, boost::ref(endPathsToBeDropped), _1));
00729     scheduledEndPaths.erase(endAfterRemove, scheduledEndPaths.end());
00730     proc_pset.addParameter<vstring>(std::string("@end_paths"), scheduledEndPaths);
00731   }
00732 
00733   void
00734   Schedule::limitOutput(ParameterSet const& proc_pset, BranchIDLists const& branchIDLists) {
00735     std::string const output("output");
00736 
00737     ParameterSet const& maxEventsPSet = proc_pset.getUntrackedParameterSet("maxEvents", ParameterSet());
00738     int maxEventSpecs = 0;
00739     int maxEventsOut = -1;
00740     ParameterSet const* vMaxEventsOut = 0;
00741     std::vector<std::string> intNamesE = maxEventsPSet.getParameterNamesForType<int>(false);
00742     if (search_all(intNamesE, output)) {
00743       maxEventsOut = maxEventsPSet.getUntrackedParameter<int>(output);
00744       ++maxEventSpecs;
00745     }
00746     std::vector<std::string> psetNamesE;
00747     maxEventsPSet.getParameterSetNames(psetNamesE, false);
00748     if (search_all(psetNamesE, output)) {
00749       vMaxEventsOut = &maxEventsPSet.getUntrackedParameterSet(output);
00750       ++maxEventSpecs;
00751     }
00752 
00753     if (maxEventSpecs > 1) {
00754       throw Exception(errors::Configuration) <<
00755         "\nAt most, one form of 'output' may appear in the 'maxEvents' parameter set";
00756     }
00757 
00758     for (AllOutputWorkers::const_iterator it = all_output_workers_.begin(), itEnd = all_output_workers_.end();
00759         it != itEnd; ++it) {
00760       OutputModuleDescription desc(branchIDLists, maxEventsOut);
00761       if (vMaxEventsOut != 0 && !vMaxEventsOut->empty()) {
00762         std::string moduleLabel = (*it)->description().moduleLabel();
00763         try {
00764           desc.maxEvents_ = vMaxEventsOut->getUntrackedParameter<int>(moduleLabel);
00765         } catch (Exception const&) {
00766           throw Exception(errors::Configuration) <<
00767             "\nNo entry in 'maxEvents' for output module label '" << moduleLabel << "'.\n";
00768         }
00769       }
00770       (*it)->configure(desc);
00771     }
00772   }
00773 
00774   bool Schedule::terminate() const {
00775     if (all_output_workers_.empty()) {
00776       return false;
00777     }
00778     for (AllOutputWorkers::const_iterator it = all_output_workers_.begin(),
00779          itEnd = all_output_workers_.end();
00780          it != itEnd; ++it) {
00781       if (!(*it)->limitReached()) {
00782         // Found an output module that has not reached output event count.
00783         return false;
00784       }
00785     }
00786     LogInfo("SuccessfulTermination")
00787       << "The job is terminating successfully because each output module\n"
00788       << "has reached its configured limit.\n";
00789     return true;
00790   }
00791 
00792   void Schedule::fillWorkers(ParameterSet& proc_pset,
00793                              ProductRegistry& preg,
00794                              boost::shared_ptr<ProcessConfiguration const> processConfiguration,
00795                              std::string const& name,
00796                              bool ignoreFilters,
00797                              PathWorkers& out,
00798                              vstring* labelsOnPaths) {
00799     vstring modnames = proc_pset.getParameter<vstring>(name);
00800     vstring::iterator it(modnames.begin()), ie(modnames.end());
00801     PathWorkers tmpworkers;
00802 
00803     for (; it != ie; ++it) {
00804 
00805       if (labelsOnPaths) labelsOnPaths->push_back(*it);
00806 
00807       WorkerInPath::FilterAction filterAction = WorkerInPath::Normal;
00808       if ((*it)[0] == '!')       filterAction = WorkerInPath::Veto;
00809       else if ((*it)[0] == '-')  filterAction = WorkerInPath::Ignore;
00810 
00811       std::string moduleLabel = *it;
00812       if (filterAction != WorkerInPath::Normal) moduleLabel.erase(0, 1);
00813 
00814       bool isTracked;
00815       ParameterSet* modpset = proc_pset.getPSetForUpdate(moduleLabel, isTracked);
00816       if (modpset == 0) {
00817         std::string pathType("endpath");
00818         if (!search_all(end_path_name_list_, name)) {
00819           pathType = std::string("path");
00820         }
00821         throw Exception(errors::Configuration) <<
00822           "The unknown module label \"" << moduleLabel <<
00823           "\" appears in " << pathType << " \"" << name <<
00824           "\"\n please check spelling or remove that label from the path.";
00825       }
00826       assert(isTracked);
00827 
00828       WorkerParams params(proc_pset, modpset, preg, processConfiguration, *act_table_);
00829       Worker* worker = worker_reg_.getWorker(params, moduleLabel);
00830       if (ignoreFilters && filterAction != WorkerInPath::Ignore && worker->moduleType()==Worker::kFilter) {
00831         // We have a filter on an end path, and the filter is not explicitly ignored.
00832         // See if the filter is allowed.
00833         std::vector<std::string> allowed_filters = proc_pset.getUntrackedParameter<vstring>("@filters_on_endpaths");
00834         if (!search_all(allowed_filters, worker->description().moduleName())) {
00835           // Filter is not allowed. Ignore the result, and issue a warning.
00836           filterAction = WorkerInPath::Ignore;
00837           LogWarning("FilterOnEndPath")
00838             << "The EDFilter '" << worker->description().moduleName() << "' with module label '" << moduleLabel << "' appears on EndPath '" << name << "'.\n"
00839             << "The return value of the filter will be ignored.\n"
00840             << "To suppress this warning, either remove the filter from the endpath,\n"
00841             << "or explicitly ignore it in the configuration by using cms.ignore().\n";
00842         }
00843       }
00844       tmpworkers.emplace_back(worker, filterAction);
00845     }
00846 
00847     out.swap(tmpworkers);
00848   }
00849 
00850   void Schedule::fillTrigPath(ParameterSet& proc_pset,
00851                               ProductRegistry& preg,
00852                               boost::shared_ptr<ProcessConfiguration const> processConfiguration,
00853                               int bitpos, std::string const& name, TrigResPtr trptr,
00854                               vstring* labelsOnTriggerPaths) {
00855     PathWorkers tmpworkers;
00856     Workers holder;
00857     fillWorkers(proc_pset, preg, processConfiguration, name, false, tmpworkers, labelsOnTriggerPaths);
00858 
00859     for (PathWorkers::iterator wi(tmpworkers.begin()),
00860           we(tmpworkers.end()); wi != we; ++wi) {
00861       holder.push_back(wi->getWorker());
00862     }
00863 
00864     // an empty path will cause an extra bit that is not used
00865     if (!tmpworkers.empty()) {
00866       Path p(bitpos, name, tmpworkers, trptr, *act_table_, actReg_, false);
00867       if (wantSummary_) {
00868         p.useStopwatch();
00869       }
00870       trig_paths_.push_back(p);
00871     } else {
00872       empty_trig_paths_.push_back(bitpos);
00873       empty_trig_path_names_.push_back(name);
00874     }
00875     for_all(holder, boost::bind(&Schedule::addToAllWorkers, this, _1));
00876   }
00877 
00878   void Schedule::fillEndPath(ParameterSet& proc_pset,
00879                              ProductRegistry& preg,
00880                              boost::shared_ptr<ProcessConfiguration const> processConfiguration,
00881                              int bitpos, std::string const& name) {
00882     PathWorkers tmpworkers;
00883     fillWorkers(proc_pset, preg, processConfiguration, name, true, tmpworkers, 0);
00884     Workers holder;
00885 
00886     for (PathWorkers::iterator wi(tmpworkers.begin()), we(tmpworkers.end()); wi != we; ++wi) {
00887       holder.push_back(wi->getWorker());
00888     }
00889 
00890     if (!tmpworkers.empty()) {
00891       Path p(bitpos, name, tmpworkers, endpath_results_, *act_table_, actReg_, true);
00892       if (wantSummary_) {
00893         p.useStopwatch();
00894       }
00895       end_paths_.push_back(p);
00896     }
00897     for_all(holder, boost::bind(&Schedule::addToAllWorkers, this, _1));
00898   }
00899 
00900   void Schedule::endJob(ExceptionCollector & collector) {
00901     bool failure = false;
00902     AllWorkers::iterator ai(workersBegin()), ae(workersEnd());
00903     for (; ai != ae; ++ai) {
00904       try {
00905         try {
00906           (*ai)->endJob();
00907         }
00908         catch (cms::Exception& e) { throw; }
00909         catch (std::bad_alloc& bda) { convertException::badAllocToEDM(); }
00910         catch (std::exception& e) { convertException::stdToEDM(e); }
00911         catch (std::string& s) { convertException::stringToEDM(s); }
00912         catch (char const* c) { convertException::charPtrToEDM(c); }
00913         catch (...) { convertException::unknownToEDM(); }
00914       }      
00915       catch (cms::Exception const& ex) {
00916         collector.addException(ex);
00917         failure = true;
00918       }
00919     }
00920     if (failure) {
00921       return;
00922     }
00923 
00924     if (wantSummary_ == false) return;
00925 
00926     TrigPaths::const_iterator pi, pe;
00927 
00928     // The trigger report (pass/fail etc.):
00929 
00930     LogVerbatim("FwkSummary") << "";
00931     LogVerbatim("FwkSummary") << "TrigReport " << "---------- Event  Summary ------------";
00932     if(!trig_paths_.empty()) {
00933       LogVerbatim("FwkSummary") << "TrigReport"
00934                                 << " Events total = " << totalEvents()
00935                                 << " passed = " << totalEventsPassed()
00936                                 << " failed = " << (totalEventsFailed())
00937                                 << "";
00938     } else {
00939       LogVerbatim("FwkSummary") << "TrigReport"
00940                                 << " Events total = " << totalEvents()
00941                                 << " passed = " << totalEvents()
00942                                 << " failed = 0";
00943     }
00944 
00945     LogVerbatim("FwkSummary") << "";
00946     LogVerbatim("FwkSummary") << "TrigReport " << "---------- Path   Summary ------------";
00947     LogVerbatim("FwkSummary") << "TrigReport "
00948                               << std::right << std::setw(10) << "Trig Bit#" << " "
00949                               << std::right << std::setw(10) << "Run" << " "
00950                               << std::right << std::setw(10) << "Passed" << " "
00951                               << std::right << std::setw(10) << "Failed" << " "
00952                               << std::right << std::setw(10) << "Error" << " "
00953                               << "Name" << "";
00954     pi = trig_paths_.begin();
00955     pe = trig_paths_.end();
00956     for (; pi != pe; ++pi) {
00957       LogVerbatim("FwkSummary") << "TrigReport "
00958                                 << std::right << std::setw(5) << 1
00959                                 << std::right << std::setw(5) << pi->bitPosition() << " "
00960                                 << std::right << std::setw(10) << pi->timesRun() << " "
00961                                 << std::right << std::setw(10) << pi->timesPassed() << " "
00962                                 << std::right << std::setw(10) << pi->timesFailed() << " "
00963                                 << std::right << std::setw(10) << pi->timesExcept() << " "
00964                                 << pi->name() << "";
00965     }
00966 
00967     std::vector<int>::const_iterator epi = empty_trig_paths_.begin();
00968     std::vector<int>::const_iterator epe = empty_trig_paths_.end();
00969     std::vector<std::string>::const_iterator  epn = empty_trig_path_names_.begin();
00970     for (; epi != epe; ++epi, ++epn) {
00971 
00972       LogVerbatim("FwkSummary") << "TrigReport "
00973                                 << std::right << std::setw(5) << 1
00974                                 << std::right << std::setw(5) << *epi << " "
00975                                 << std::right << std::setw(10) << totalEvents() << " "
00976                                 << std::right << std::setw(10) << totalEvents() << " "
00977                                 << std::right << std::setw(10) << 0 << " "
00978                                 << std::right << std::setw(10) << 0 << " "
00979                                 << *epn << "";
00980     }
00981 
00982     LogVerbatim("FwkSummary") << "";
00983     LogVerbatim("FwkSummary") << "TrigReport " << "-------End-Path   Summary ------------";
00984     LogVerbatim("FwkSummary") << "TrigReport "
00985                               << std::right << std::setw(10) << "Trig Bit#" << " "
00986                               << std::right << std::setw(10) << "Run" << " "
00987                               << std::right << std::setw(10) << "Passed" << " "
00988                               << std::right << std::setw(10) << "Failed" << " "
00989                               << std::right << std::setw(10) << "Error" << " "
00990                               << "Name" << "";
00991     pi = end_paths_.begin();
00992     pe = end_paths_.end();
00993     for (; pi != pe; ++pi) {
00994       LogVerbatim("FwkSummary") << "TrigReport "
00995                                 << std::right << std::setw(5) << 0
00996                                 << std::right << std::setw(5) << pi->bitPosition() << " "
00997                                 << std::right << std::setw(10) << pi->timesRun() << " "
00998                                 << std::right << std::setw(10) << pi->timesPassed() << " "
00999                                 << std::right << std::setw(10) << pi->timesFailed() << " "
01000                                 << std::right << std::setw(10) << pi->timesExcept() << " "
01001                                 << pi->name() << "";
01002     }
01003 
01004     pi = trig_paths_.begin();
01005     pe = trig_paths_.end();
01006     for (; pi != pe; ++pi) {
01007       LogVerbatim("FwkSummary") << "";
01008       LogVerbatim("FwkSummary") << "TrigReport " << "---------- Modules in Path: " << pi->name() << " ------------";
01009       LogVerbatim("FwkSummary") << "TrigReport "
01010                                 << std::right << std::setw(10) << "Trig Bit#" << " "
01011                                 << std::right << std::setw(10) << "Visited" << " "
01012                                 << std::right << std::setw(10) << "Passed" << " "
01013                                 << std::right << std::setw(10) << "Failed" << " "
01014                                 << std::right << std::setw(10) << "Error" << " "
01015                                 << "Name" << "";
01016 
01017       for (unsigned int i = 0; i < pi->size(); ++i) {
01018         LogVerbatim("FwkSummary") << "TrigReport "
01019                                   << std::right << std::setw(5) << 1
01020                                   << std::right << std::setw(5) << pi->bitPosition() << " "
01021                                   << std::right << std::setw(10) << pi->timesVisited(i) << " "
01022                                   << std::right << std::setw(10) << pi->timesPassed(i) << " "
01023                                   << std::right << std::setw(10) << pi->timesFailed(i) << " "
01024                                   << std::right << std::setw(10) << pi->timesExcept(i) << " "
01025                                   << pi->getWorker(i)->description().moduleLabel() << "";
01026       }
01027     }
01028 
01029     pi = end_paths_.begin();
01030     pe = end_paths_.end();
01031     for (; pi != pe; ++pi) {
01032       LogVerbatim("FwkSummary") << "";
01033       LogVerbatim("FwkSummary") << "TrigReport " << "------ Modules in End-Path: " << pi->name() << " ------------";
01034       LogVerbatim("FwkSummary") << "TrigReport "
01035                                 << std::right << std::setw(10) << "Trig Bit#" << " "
01036                                 << std::right << std::setw(10) << "Visited" << " "
01037                                 << std::right << std::setw(10) << "Passed" << " "
01038                                 << std::right << std::setw(10) << "Failed" << " "
01039                                 << std::right << std::setw(10) << "Error" << " "
01040                                 << "Name" << "";
01041 
01042       for (unsigned int i = 0; i < pi->size(); ++i) {
01043         LogVerbatim("FwkSummary") << "TrigReport "
01044                                   << std::right << std::setw(5) << 0
01045                                   << std::right << std::setw(5) << pi->bitPosition() << " "
01046                                   << std::right << std::setw(10) << pi->timesVisited(i) << " "
01047                                   << std::right << std::setw(10) << pi->timesPassed(i) << " "
01048                                   << std::right << std::setw(10) << pi->timesFailed(i) << " "
01049                                   << std::right << std::setw(10) << pi->timesExcept(i) << " "
01050                                   << pi->getWorker(i)->description().moduleLabel() << "";
01051       }
01052     }
01053 
01054     LogVerbatim("FwkSummary") << "";
01055     LogVerbatim("FwkSummary") << "TrigReport " << "---------- Module Summary ------------";
01056     LogVerbatim("FwkSummary") << "TrigReport "
01057                               << std::right << std::setw(10) << "Visited" << " "
01058                               << std::right << std::setw(10) << "Run" << " "
01059                               << std::right << std::setw(10) << "Passed" << " "
01060                               << std::right << std::setw(10) << "Failed" << " "
01061                               << std::right << std::setw(10) << "Error" << " "
01062                               << "Name" << "";
01063     ai = workersBegin();
01064     ae = workersEnd();
01065     for (; ai != ae; ++ai) {
01066       LogVerbatim("FwkSummary") << "TrigReport "
01067                                 << std::right << std::setw(10) << (*ai)->timesVisited() << " "
01068                                 << std::right << std::setw(10) << (*ai)->timesRun() << " "
01069                                 << std::right << std::setw(10) << (*ai)->timesPassed() << " "
01070                                 << std::right << std::setw(10) << (*ai)->timesFailed() << " "
01071                                 << std::right << std::setw(10) << (*ai)->timesExcept() << " "
01072                                 << (*ai)->description().moduleLabel() << "";
01073 
01074     }
01075     LogVerbatim("FwkSummary") << "";
01076 
01077     // The timing report (CPU and Real Time):
01078 
01079     LogVerbatim("FwkSummary") << "TimeReport " << "---------- Event  Summary ---[sec]----";
01080     LogVerbatim("FwkSummary") << "TimeReport"
01081                               << std::setprecision(6) << std::fixed
01082                               << " CPU/event = " << timeCpuReal().first/std::max(1, totalEvents())
01083                               << " Real/event = " << timeCpuReal().second/std::max(1, totalEvents())
01084                               << "";
01085 
01086     LogVerbatim("FwkSummary") << "";
01087     LogVerbatim("FwkSummary") << "TimeReport " << "---------- Path   Summary ---[sec]----";
01088     LogVerbatim("FwkSummary") << "TimeReport "
01089                               << std::right << std::setw(22) << "per event "
01090                               << std::right << std::setw(22) << "per path-run "
01091                               << "";
01092     LogVerbatim("FwkSummary") << "TimeReport "
01093                               << std::right << std::setw(10) << "CPU" << " "
01094                               << std::right << std::setw(10) << "Real" << " "
01095                               << std::right << std::setw(10) << "CPU" << " "
01096                               << std::right << std::setw(10) << "Real" << " "
01097                               << "Name" << "";
01098     pi = trig_paths_.begin();
01099     pe = trig_paths_.end();
01100     for (; pi != pe; ++pi) {
01101       LogVerbatim("FwkSummary") << "TimeReport "
01102                                 << std::setprecision(6) << std::fixed
01103                                 << std::right << std::setw(10) << pi->timeCpuReal().first/std::max(1, totalEvents()) << " "
01104                                 << std::right << std::setw(10) << pi->timeCpuReal().second/std::max(1, totalEvents()) << " "
01105                                 << std::right << std::setw(10) << pi->timeCpuReal().first/std::max(1, pi->timesRun()) << " "
01106                                 << std::right << std::setw(10) << pi->timeCpuReal().second/std::max(1, pi->timesRun()) << " "
01107                                 << pi->name() << "";
01108     }
01109     LogVerbatim("FwkSummary") << "TimeReport "
01110                               << std::right << std::setw(10) << "CPU" << " "
01111                               << std::right << std::setw(10) << "Real" << " "
01112                               << std::right << std::setw(10) << "CPU" << " "
01113                               << std::right << std::setw(10) << "Real" << " "
01114                               << "Name" << "";
01115     LogVerbatim("FwkSummary") << "TimeReport "
01116                               << std::right << std::setw(22) << "per event "
01117                               << std::right << std::setw(22) << "per path-run "
01118                               << "";
01119 
01120     LogVerbatim("FwkSummary") << "";
01121     LogVerbatim("FwkSummary") << "TimeReport " << "-------End-Path   Summary ---[sec]----";
01122     LogVerbatim("FwkSummary") << "TimeReport "
01123                               << std::right << std::setw(22) << "per event "
01124                               << std::right << std::setw(22) << "per endpath-run "
01125                               << "";
01126     LogVerbatim("FwkSummary") << "TimeReport "
01127                               << std::right << std::setw(10) << "CPU" << " "
01128                               << std::right << std::setw(10) << "Real" << " "
01129                               << std::right << std::setw(10) << "CPU" << " "
01130                               << std::right << std::setw(10) << "Real" << " "
01131                               << "Name" << "";
01132     pi = end_paths_.begin();
01133     pe = end_paths_.end();
01134     for (; pi != pe; ++pi) {
01135       LogVerbatim("FwkSummary") << "TimeReport "
01136                                 << std::setprecision(6) << std::fixed
01137                                 << std::right << std::setw(10) << pi->timeCpuReal().first/std::max(1, totalEvents()) << " "
01138                                 << std::right << std::setw(10) << pi->timeCpuReal().second/std::max(1, totalEvents()) << " "
01139                                 << std::right << std::setw(10) << pi->timeCpuReal().first/std::max(1, pi->timesRun()) << " "
01140                                 << std::right << std::setw(10) << pi->timeCpuReal().second/std::max(1, pi->timesRun()) << " "
01141                                 << pi->name() << "";
01142     }
01143     LogVerbatim("FwkSummary") << "TimeReport "
01144                               << std::right << std::setw(10) << "CPU" << " "
01145                               << std::right << std::setw(10) << "Real" << " "
01146                               << std::right << std::setw(10) << "CPU" << " "
01147                               << std::right << std::setw(10) << "Real" << " "
01148                               << "Name" << "";
01149     LogVerbatim("FwkSummary") << "TimeReport "
01150                               << std::right << std::setw(22) << "per event "
01151                               << std::right << std::setw(22) << "per endpath-run "
01152                               << "";
01153 
01154     pi = trig_paths_.begin();
01155     pe = trig_paths_.end();
01156     for (; pi != pe; ++pi) {
01157       LogVerbatim("FwkSummary") << "";
01158       LogVerbatim("FwkSummary") << "TimeReport " << "---------- Modules in Path: " << pi->name() << " ---[sec]----";
01159       LogVerbatim("FwkSummary") << "TimeReport "
01160                                 << std::right << std::setw(22) << "per event "
01161                                 << std::right << std::setw(22) << "per module-visit "
01162                                 << "";
01163       LogVerbatim("FwkSummary") << "TimeReport "
01164                                 << std::right << std::setw(10) << "CPU" << " "
01165                                 << std::right << std::setw(10) << "Real" << " "
01166                                 << std::right << std::setw(10) << "CPU" << " "
01167                                 << std::right << std::setw(10) << "Real" << " "
01168                                 << "Name" << "";
01169       for (unsigned int i = 0; i < pi->size(); ++i) {
01170         LogVerbatim("FwkSummary") << "TimeReport "
01171                                   << std::setprecision(6) << std::fixed
01172                                   << std::right << std::setw(10) << pi->timeCpuReal(i).first/std::max(1, totalEvents()) << " "
01173                                   << std::right << std::setw(10) << pi->timeCpuReal(i).second/std::max(1, totalEvents()) << " "
01174                                   << std::right << std::setw(10) << pi->timeCpuReal(i).first/std::max(1, pi->timesVisited(i)) << " "
01175                                   << std::right << std::setw(10) << pi->timeCpuReal(i).second/std::max(1, pi->timesVisited(i)) << " "
01176                                   << pi->getWorker(i)->description().moduleLabel() << "";
01177       }
01178     }
01179     LogVerbatim("FwkSummary") << "TimeReport "
01180                               << std::right << std::setw(10) << "CPU" << " "
01181                               << std::right << std::setw(10) << "Real" << " "
01182                               << std::right << std::setw(10) << "CPU" << " "
01183                               << std::right << std::setw(10) << "Real" << " "
01184                               << "Name" << "";
01185     LogVerbatim("FwkSummary") << "TimeReport "
01186                               << std::right << std::setw(22) << "per event "
01187                               << std::right << std::setw(22) << "per module-visit "
01188                               << "";
01189 
01190     pi = end_paths_.begin();
01191     pe = end_paths_.end();
01192     for (; pi != pe; ++pi) {
01193       LogVerbatim("FwkSummary") << "";
01194       LogVerbatim("FwkSummary") << "TimeReport " << "------ Modules in End-Path: " << pi->name() << " ---[sec]----";
01195       LogVerbatim("FwkSummary") << "TimeReport "
01196                                 << std::right << std::setw(22) << "per event "
01197                                 << std::right << std::setw(22) << "per module-visit "
01198                                 << "";
01199       LogVerbatim("FwkSummary") << "TimeReport "
01200                                 << std::right << std::setw(10) << "CPU" << " "
01201                                 << std::right << std::setw(10) << "Real" << " "
01202                                 << std::right << std::setw(10) << "CPU" << " "
01203                                 << std::right << std::setw(10) << "Real" << " "
01204                                 << "Name" << "";
01205       for (unsigned int i = 0; i < pi->size(); ++i) {
01206         LogVerbatim("FwkSummary") << "TimeReport "
01207                                   << std::setprecision(6) << std::fixed
01208                                   << std::right << std::setw(10) << pi->timeCpuReal(i).first/std::max(1, totalEvents()) << " "
01209                                   << std::right << std::setw(10) << pi->timeCpuReal(i).second/std::max(1, totalEvents()) << " "
01210                                   << std::right << std::setw(10) << pi->timeCpuReal(i).first/std::max(1, pi->timesVisited(i)) << " "
01211                                   << std::right << std::setw(10) << pi->timeCpuReal(i).second/std::max(1, pi->timesVisited(i)) << " "
01212                                   << pi->getWorker(i)->description().moduleLabel() << "";
01213       }
01214     }
01215     LogVerbatim("FwkSummary") << "TimeReport "
01216                               << std::right << std::setw(10) << "CPU" << " "
01217                               << std::right << std::setw(10) << "Real" << " "
01218                               << std::right << std::setw(10) << "CPU" << " "
01219                               << std::right << std::setw(10) << "Real" << " "
01220                               << "Name" << "";
01221     LogVerbatim("FwkSummary") << "TimeReport "
01222                               << std::right << std::setw(22) << "per event "
01223                               << std::right << std::setw(22) << "per module-visit "
01224                               << "";
01225 
01226     LogVerbatim("FwkSummary") << "";
01227     LogVerbatim("FwkSummary") << "TimeReport " << "---------- Module Summary ---[sec]----";
01228     LogVerbatim("FwkSummary") << "TimeReport "
01229                               << std::right << std::setw(22) << "per event "
01230                               << std::right << std::setw(22) << "per module-run "
01231                               << std::right << std::setw(22) << "per module-visit "
01232                               << "";
01233     LogVerbatim("FwkSummary") << "TimeReport "
01234                               << std::right << std::setw(10) << "CPU" << " "
01235                               << std::right << std::setw(10) << "Real" << " "
01236                               << std::right << std::setw(10) << "CPU" << " "
01237                               << std::right << std::setw(10) << "Real" << " "
01238                               << std::right << std::setw(10) << "CPU" << " "
01239                               << std::right << std::setw(10) << "Real" << " "
01240                               << "Name" << "";
01241     ai = workersBegin();
01242     ae = workersEnd();
01243     for (; ai != ae; ++ai) {
01244       LogVerbatim("FwkSummary") << "TimeReport "
01245                                 << std::setprecision(6) << std::fixed
01246                                 << std::right << std::setw(10) << (*ai)->timeCpuReal().first/std::max(1, totalEvents()) << " "
01247                                 << std::right << std::setw(10) << (*ai)->timeCpuReal().second/std::max(1, totalEvents()) << " "
01248                                 << std::right << std::setw(10) << (*ai)->timeCpuReal().first/std::max(1, (*ai)->timesRun()) << " "
01249                                 << std::right << std::setw(10) << (*ai)->timeCpuReal().second/std::max(1, (*ai)->timesRun()) << " "
01250                                 << std::right << std::setw(10) << (*ai)->timeCpuReal().first/std::max(1, (*ai)->timesVisited()) << " "
01251                                 << std::right << std::setw(10) << (*ai)->timeCpuReal().second/std::max(1, (*ai)->timesVisited()) << " "
01252                                 << (*ai)->description().moduleLabel() << "";
01253     }
01254     LogVerbatim("FwkSummary") << "TimeReport "
01255                               << std::right << std::setw(10) << "CPU" << " "
01256                               << std::right << std::setw(10) << "Real" << " "
01257                               << std::right << std::setw(10) << "CPU" << " "
01258                               << std::right << std::setw(10) << "Real" << " "
01259                               << std::right << std::setw(10) << "CPU" << " "
01260                               << std::right << std::setw(10) << "Real" << " "
01261                               << "Name" << "";
01262     LogVerbatim("FwkSummary") << "TimeReport "
01263                               << std::right << std::setw(22) << "per event "
01264                               << std::right << std::setw(22) << "per module-run "
01265                               << std::right << std::setw(22) << "per module-visit "
01266                               << "";
01267 
01268     LogVerbatim("FwkSummary") << "";
01269     LogVerbatim("FwkSummary") << "T---Report end!" << "";
01270     LogVerbatim("FwkSummary") << "";
01271   }
01272 
01273   void Schedule::closeOutputFiles() {
01274     for_all(all_output_workers_, boost::bind(&OutputWorker::closeFile, _1));
01275   }
01276 
01277   void Schedule::openNewOutputFilesIfNeeded() {
01278     for_all(all_output_workers_, boost::bind(&OutputWorker::openNewFileIfNeeded, _1));
01279   }
01280 
01281   void Schedule::openOutputFiles(FileBlock& fb) {
01282     for_all(all_output_workers_, boost::bind(&OutputWorker::openFile, _1, boost::cref(fb)));
01283   }
01284 
01285   void Schedule::writeRun(RunPrincipal const& rp) {
01286     for_all(all_output_workers_, boost::bind(&OutputWorker::writeRun, _1, boost::cref(rp)));
01287   }
01288 
01289   void Schedule::writeLumi(LuminosityBlockPrincipal const& lbp) {
01290     for_all(all_output_workers_, boost::bind(&OutputWorker::writeLumi, _1, boost::cref(lbp)));
01291   }
01292 
01293   bool Schedule::shouldWeCloseOutput() const {
01294     // Return true iff at least one output module returns true.
01295     return (std::find_if (all_output_workers_.begin(), all_output_workers_.end(),
01296                      boost::bind(&OutputWorker::shouldWeCloseFile, _1))
01297                      != all_output_workers_.end());
01298   }
01299 
01300   void Schedule::respondToOpenInputFile(FileBlock const& fb) {
01301     for_all(all_workers_, boost::bind(&Worker::respondToOpenInputFile, _1, boost::cref(fb)));
01302   }
01303 
01304   void Schedule::respondToCloseInputFile(FileBlock const& fb) {
01305     for_all(all_workers_, boost::bind(&Worker::respondToCloseInputFile, _1, boost::cref(fb)));
01306   }
01307 
01308   void Schedule::respondToOpenOutputFiles(FileBlock const& fb) {
01309     for_all(all_workers_, boost::bind(&Worker::respondToOpenOutputFiles, _1, boost::cref(fb)));
01310   }
01311 
01312   void Schedule::respondToCloseOutputFiles(FileBlock const& fb) {
01313     for_all(all_workers_, boost::bind(&Worker::respondToCloseOutputFiles, _1, boost::cref(fb)));
01314   }
01315 
01316   void Schedule::beginJob(ProductRegistry const& iRegistry) {
01317     auto const runLookup = iRegistry.productLookup(InRun);
01318     auto const lumiLookup = iRegistry.productLookup(InLumi);
01319     auto const eventLookup = iRegistry.productLookup(InEvent);
01320     for(auto & worker: all_workers_) {
01321       worker->updateLookup(InRun,*runLookup);
01322       worker->updateLookup(InLumi,*lumiLookup);
01323       worker->updateLookup(InEvent,*eventLookup);
01324     }
01325     
01326     for_all(all_workers_, boost::bind(&Worker::beginJob, _1));
01327     loadMissingDictionaries();
01328   }
01329 
01330   void Schedule::preForkReleaseResources() {
01331     for_all(all_workers_, boost::bind(&Worker::preForkReleaseResources, _1));
01332   }
01333   void Schedule::postForkReacquireResources(unsigned int iChildIndex, unsigned int iNumberOfChildren) {
01334     for_all(all_workers_, boost::bind(&Worker::postForkReacquireResources, _1, iChildIndex, iNumberOfChildren));
01335   }
01336 
01337   bool Schedule::changeModule(std::string const& iLabel,
01338                               ParameterSet const& iPSet) {
01339     Worker* found = 0;
01340     for (AllWorkers::const_iterator it=all_workers_.begin(), itEnd=all_workers_.end();
01341         it != itEnd; ++it) {
01342       if ((*it)->description().moduleLabel() == iLabel) {
01343         found = *it;
01344         break;
01345       }
01346     }
01347     if (0 == found) {
01348       return false;
01349     }
01350 
01351     std::auto_ptr<Maker> wm(MakerPluginFactory::get()->create(found->description().moduleName()));
01352     wm->swapModule(found, iPSet);
01353     found->beginJob();
01354     return true;
01355   }
01356 
01357   std::vector<ModuleDescription const*>
01358   Schedule::getAllModuleDescriptions() const {
01359     AllWorkers::const_iterator i(workersBegin());
01360     AllWorkers::const_iterator e(workersEnd());
01361 
01362     std::vector<ModuleDescription const*> result;
01363     result.reserve(all_workers_.size());
01364 
01365     for (; i != e; ++i) {
01366       ModuleDescription const* p = (*i)->descPtr();
01367       result.push_back(p);
01368     }
01369     return result;
01370   }
01371 
01372   void
01373   Schedule::availablePaths(std::vector<std::string>& oLabelsToFill) const {
01374     oLabelsToFill.reserve(trig_paths_.size());
01375     std::transform(trig_paths_.begin(),
01376                    trig_paths_.end(),
01377                    std::back_inserter(oLabelsToFill),
01378                    boost::bind(&Path::name, _1));
01379   }
01380 
01381   void
01382   Schedule::modulesInPath(std::string const& iPathLabel,
01383                           std::vector<std::string>& oLabelsToFill) const {
01384     TrigPaths::const_iterator itFound =
01385     std::find_if (trig_paths_.begin(),
01386                  trig_paths_.end(),
01387                  boost::bind(std::equal_to<std::string>(),
01388                              iPathLabel,
01389                              boost::bind(&Path::name, _1)));
01390     if (itFound!=trig_paths_.end()) {
01391       oLabelsToFill.reserve(itFound->size());
01392       for (size_t i = 0; i < itFound->size(); ++i) {
01393         oLabelsToFill.push_back(itFound->getWorker(i)->description().moduleLabel());
01394       }
01395     }
01396   }
01397 
01398   void
01399   Schedule::enableEndPaths(bool active) {
01400     endpathsAreActive_ = active;
01401   }
01402 
01403   bool
01404   Schedule::endPathsEnabled() const {
01405     return endpathsAreActive_;
01406   }
01407 
01408   void
01409   fillModuleInPathSummary(Path const&, ModuleInPathSummary&) {
01410   }
01411 
01412   void
01413   fillModuleInPathSummary(Path const& path,
01414                           size_t which,
01415                           ModuleInPathSummary& sum) {
01416     sum.timesVisited = path.timesVisited(which);
01417     sum.timesPassed  = path.timesPassed(which);
01418     sum.timesFailed  = path.timesFailed(which);
01419     sum.timesExcept  = path.timesExcept(which);
01420     sum.moduleLabel  = path.getWorker(which)->description().moduleLabel();
01421   }
01422 
01423   void
01424   fillPathSummary(Path const& path, PathSummary& sum) {
01425     sum.name        = path.name();
01426     sum.bitPosition = path.bitPosition();
01427     sum.timesRun    = path.timesRun();
01428     sum.timesPassed = path.timesPassed();
01429     sum.timesFailed = path.timesFailed();
01430     sum.timesExcept = path.timesExcept();
01431 
01432     Path::size_type sz = path.size();
01433     std::vector<ModuleInPathSummary> temp(sz);
01434     for (size_t i = 0; i != sz; ++i) {
01435       fillModuleInPathSummary(path, i, temp[i]);
01436     }
01437     sum.moduleInPathSummaries.swap(temp);
01438   }
01439 
01440   void
01441   fillWorkerSummaryAux(Worker const& w, WorkerSummary& sum) {
01442     sum.timesVisited = w.timesVisited();
01443     sum.timesRun     = w.timesRun();
01444     sum.timesPassed  = w.timesPassed();
01445     sum.timesFailed  = w.timesFailed();
01446     sum.timesExcept  = w.timesExcept();
01447     sum.moduleLabel  = w.description().moduleLabel();
01448   }
01449 
01450   void
01451   fillWorkerSummary(Worker const* pw, WorkerSummary& sum) {
01452     fillWorkerSummaryAux(*pw, sum);
01453   }
01454 
01455   void
01456   Schedule::getTriggerReport(TriggerReport& rep) const {
01457     rep.eventSummary.totalEvents = totalEvents();
01458     rep.eventSummary.totalEventsPassed = totalEventsPassed();
01459     rep.eventSummary.totalEventsFailed = totalEventsFailed();
01460 
01461     fill_summary(trig_paths_,  rep.trigPathSummaries, &fillPathSummary);
01462     fill_summary(end_paths_,   rep.endPathSummaries,  &fillPathSummary);
01463     fill_summary(all_workers_, rep.workerSummaries,   &fillWorkerSummary);
01464   }
01465 
01466   void
01467   Schedule::clearCounters() {
01468     total_events_ = total_passed_ = 0;
01469     for_all(trig_paths_, boost::bind(&Path::clearCounters, _1));
01470     for_all(end_paths_, boost::bind(&Path::clearCounters, _1));
01471     for_all(all_workers_, boost::bind(&Worker::clearCounters, _1));
01472   }
01473 
01474   void
01475   Schedule::resetAll() {
01476     for_all(all_workers_, boost::bind(&Worker::reset, _1));
01477     results_->reset();
01478     endpath_results_->reset();
01479   }
01480 
01481   void
01482   Schedule::addToAllWorkers(Worker* w) {
01483     if (!search_all(all_workers_, w)) {
01484       if (wantSummary_) {
01485         w->useStopwatch();
01486       }
01487       all_workers_.push_back(w);
01488     }
01489   }
01490 
01491   void
01492   Schedule::setupOnDemandSystem(EventPrincipal& ep, EventSetup const& es) {
01493     // NOTE: who owns the productdescrption?  Just copied by value
01494     unscheduled_->setEventSetup(es);
01495     ep.setUnscheduledHandler(unscheduled_);
01496   }
01497   
01498   void 
01499   Schedule::resetEarlyDelete() {
01500     //must be sure we have cleared the count first
01501     for(auto& count:earlyDeleteBranchToCount_) {
01502       count.second = 0;
01503     }
01504     //now reset based on how many helpers use that branch
01505     for(auto& index: earlyDeleteHelperToBranchIndicies_) {
01506       ++(earlyDeleteBranchToCount_[index].second);
01507     }
01508     for(auto& helper: earlyDeleteHelpers_) {
01509       helper.reset();
01510     }
01511   }
01512 
01513 }