Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2025-04-22 06:27:33

0001 #include "DataFormats/Common/interface/setIsMergeable.h"
0002 #include "DataFormats/Provenance/interface/BranchIDListHelper.h"
0003 #include "DataFormats/Provenance/interface/BranchType.h"
0004 #include "DataFormats/Provenance/interface/branchIDToProductID.h"
0005 #include "DataFormats/Provenance/interface/EventSelectionID.h"
0006 #include "DataFormats/Provenance/interface/History.h"
0007 #include "DataFormats/Provenance/interface/ParameterSetBlob.h"
0008 #include "DataFormats/Provenance/interface/ParameterSetID.h"
0009 #include "DataFormats/Provenance/interface/ProcessHistoryRegistry.h"
0010 #include "DataFormats/Provenance/interface/ProductRegistry.h"
0011 #include "DataFormats/Provenance/interface/Parentage.h"
0012 #include "DataFormats/Provenance/interface/ProductProvenance.h"
0013 #include "DataFormats/Provenance/interface/StoredProductProvenance.h"
0014 #include "DataFormats/Provenance/interface/ParentageRegistry.h"
0015 #include "FWCore/Catalog/interface/InputFileCatalog.h"
0016 #include "FWCore/ParameterSet/interface/ParameterSet.h"
0017 #include "FWCore/ParameterSet/interface/Registry.h"
0018 #include "FWCore/Services/interface/setupSiteLocalConfig.h"
0019 
0020 #include "FWCore/Utilities/interface/Algorithms.h"
0021 #include "FWCore/Utilities/interface/Exception.h"
0022 #include "FWCore/Utilities/interface/propagate_const.h"
0023 
0024 #include "TError.h"
0025 #include "TFile.h"
0026 #include "TTree.h"
0027 
0028 #include "boost/program_options.hpp"
0029 
0030 #include <cassert>
0031 #include <iostream>
0032 #include <memory>
0033 #include <map>
0034 #include <optional>
0035 #include <set>
0036 #include <sstream>
0037 #include <vector>
0038 
0039 typedef std::map<std::string, std::vector<edm::ProductDescription>> IdToBranches;
0040 typedef std::map<std::pair<std::string, std::string>, IdToBranches> ModuleToIdBranches;
0041 
0042 static std::ostream& prettyPrint(std::ostream& oStream,
0043                                  edm::ParameterSet const& iPSet,
0044                                  std::string const& iIndent,
0045                                  std::string const& iIndentDelta);
0046 
0047 static std::string const triggerResults = std::string("TriggerResults");
0048 static std::string const triggerPaths = std::string("@trigger_paths");
0049 static std::string const source = std::string("source");
0050 static std::string const input = std::string("@main_input");
0051 
0052 namespace {
0053   typedef std::map<edm::ParameterSetID, edm::ParameterSetBlob> ParameterSetMap;
0054 
0055   class HistoryNode {
0056   public:
0057     HistoryNode() = default;
0058 
0059     HistoryNode(edm::ProcessConfiguration const& iConfig,
0060                 unsigned int iSimpleId,
0061                 bool printHardwareResourcesDescription)
0062         : config_(iConfig),
0063           simpleId_(iSimpleId),
0064           printHardwareResourcesDescription_(printHardwareResourcesDescription) {}
0065 
0066     void addChild(HistoryNode const& child) { children_.push_back(child); }
0067 
0068     edm::ParameterSetID const& parameterSetID() const { return config_.parameterSetID(); }
0069 
0070     std::string const& processName() const { return config_.processName(); }
0071 
0072     std::size_t size() const { return children_.size(); }
0073 
0074     HistoryNode* lastChildAddress() { return &children_.back(); }
0075 
0076     typedef std::vector<HistoryNode>::const_iterator const_iterator;
0077     typedef std::vector<HistoryNode>::iterator iterator;
0078 
0079     iterator begin() { return children_.begin(); }
0080     iterator end() { return children_.end(); }
0081 
0082     const_iterator begin() const { return children_.begin(); }
0083     const_iterator end() const { return children_.end(); }
0084 
0085     void print(std::ostream& os) const {
0086       os << config_.processName() << " '" << config_.releaseVersion() << "' [" << simpleId_ << "]  ("
0087          << config_.parameterSetID() << ")";
0088       if (printHardwareResourcesDescription_) {
0089         auto const& hwresources = config_.hardwareResourcesDescription();
0090         os << "  (" << hwresources.microarchitecture;
0091         if (not hwresources.selectedAccelerators.empty()) {
0092           os << "; " << hwresources.selectedAccelerators.front();
0093           for (auto it = hwresources.selectedAccelerators.begin() + 1; it != hwresources.selectedAccelerators.end();
0094                ++it) {
0095             os << "," << *it;
0096           }
0097         }
0098         os << ")";
0099       }
0100       os << std::endl;
0101     }
0102 
0103     void printHistory(std::string const& iIndent = std::string("  ")) const;
0104     void printEventSetupHistory(ParameterSetMap const& iPSM,
0105                                 std::vector<std::string> const& iFindMatch,
0106                                 std::ostream& oErrorLog) const;
0107     void printOtherModulesHistory(ParameterSetMap const& iPSM,
0108                                   ModuleToIdBranches const&,
0109                                   std::vector<std::string> const& iFindMatch,
0110                                   std::ostream& oErrorLog) const;
0111     void printTopLevelPSetsHistory(ParameterSetMap const& iPSM,
0112                                    std::vector<std::string> const& iFindMatch,
0113                                    std::ostream& oErrorLog) const;
0114 
0115     edm::ProcessConfigurationID configurationID() const { return config_.id(); }
0116 
0117     static bool sort_;
0118 
0119   private:
0120     edm::ProcessConfiguration config_;
0121     std::vector<HistoryNode> children_;
0122     unsigned int simpleId_ = 0;
0123     bool printHardwareResourcesDescription_ = false;
0124   };
0125 
0126   std::ostream& operator<<(std::ostream& os, HistoryNode const& node) {
0127     node.print(os);
0128     return os;
0129   }
0130   bool HistoryNode::sort_ = false;
0131 }  // namespace
0132 
0133 std::ostream& operator<<(std::ostream& os, edm::ProcessHistory& iHist) {
0134   std::string const indentDelta("  ");
0135   std::string indent = indentDelta;
0136   for (auto const& process : iHist) {
0137     // TODO: add printout of HardwareResourcesDescription
0138     os << indent << process.processName() << " '" << process.releaseVersion() << "' (" << process.parameterSetID()
0139        << ")" << std::endl;
0140     indent += indentDelta;
0141   }
0142   return os;
0143 }
0144 
0145 void HistoryNode::printHistory(std::string const& iIndent) const {
0146   std::string const indentDelta("  ");
0147   const std::string& indent = iIndent;
0148   for (auto const& item : *this) {
0149     std::cout << indent << item;
0150     item.printHistory(indent + indentDelta);
0151   }
0152 }
0153 
0154 std::string eventSetupComponent(char const* iType,
0155                                 std::string const& iCompName,
0156                                 edm::ParameterSet const& iProcessConfig,
0157                                 std::string const& iProcessName) {
0158   std::ostringstream result;
0159   edm::ParameterSet const& pset = iProcessConfig.getParameterSet(iCompName);
0160   std::string name(pset.getParameter<std::string>("@module_label"));
0161   if (name.empty()) {
0162     name = pset.getParameter<std::string>("@module_type");
0163   }
0164 
0165   result << iType << ": " << name << " " << iProcessName << "\n"
0166          << " parameters: ";
0167   prettyPrint(result, pset, " ", " ");
0168   return result.str();
0169 }
0170 
0171 void HistoryNode::printEventSetupHistory(ParameterSetMap const& iPSM,
0172                                          std::vector<std::string> const& iFindMatch,
0173                                          std::ostream& oErrorLog) const {
0174   for (auto const& itH : *this) {
0175     //Get ParameterSet for process
0176     ParameterSetMap::const_iterator itFind = iPSM.find(itH.parameterSetID());
0177     if (itFind == iPSM.end()) {
0178       oErrorLog << "No ParameterSetID for " << itH.parameterSetID() << std::endl;
0179     } else {
0180       edm::ParameterSet processConfig(itFind->second.pset());
0181       std::vector<std::string> sourceStrings, moduleStrings;
0182       //get the sources
0183       std::vector<std::string> sources = processConfig.getParameter<std::vector<std::string>>("@all_essources");
0184       for (auto& itM : sources) {
0185         std::string retValue = eventSetupComponent("ESSource", itM, processConfig, itH.processName());
0186         bool foundMatch = true;
0187         if (!iFindMatch.empty()) {
0188           for (auto const& stringToFind : iFindMatch) {
0189             if (retValue.find(stringToFind) == std::string::npos) {
0190               foundMatch = false;
0191               break;
0192             }
0193           }
0194         }
0195         if (foundMatch) {
0196           sourceStrings.push_back(std::move(retValue));
0197         }
0198       }
0199       //get the modules
0200       std::vector<std::string> modules = processConfig.getParameter<std::vector<std::string>>("@all_esmodules");
0201       for (auto& itM : modules) {
0202         std::string retValue = eventSetupComponent("ESModule", itM, processConfig, itH.processName());
0203         bool foundMatch = true;
0204         if (!iFindMatch.empty()) {
0205           for (auto const& stringToFind : iFindMatch) {
0206             if (retValue.find(stringToFind) == std::string::npos) {
0207               foundMatch = false;
0208               break;
0209             }
0210           }
0211         }
0212         if (foundMatch) {
0213           moduleStrings.push_back(std::move(retValue));
0214         }
0215       }
0216       if (sort_) {
0217         std::sort(sourceStrings.begin(), sourceStrings.end());
0218         std::sort(moduleStrings.begin(), moduleStrings.end());
0219       }
0220       std::copy(sourceStrings.begin(), sourceStrings.end(), std::ostream_iterator<std::string>(std::cout, "\n"));
0221       std::copy(moduleStrings.begin(), moduleStrings.end(), std::ostream_iterator<std::string>(std::cout, "\n"));
0222     }
0223     itH.printEventSetupHistory(iPSM, iFindMatch, oErrorLog);
0224   }
0225 }
0226 
0227 std::string nonProducerComponent(std::string const& iCompName,
0228                                  edm::ParameterSet const& iProcessConfig,
0229                                  std::string const& iProcessName) {
0230   std::ostringstream result;
0231   edm::ParameterSet const& pset = iProcessConfig.getParameterSet(iCompName);
0232   std::string label(pset.getParameter<std::string>("@module_label"));
0233 
0234   result << "Module: " << label << " " << iProcessName << "\n"
0235          << " parameters: ";
0236   prettyPrint(result, pset, " ", " ");
0237   return result.str();
0238 }
0239 
0240 void HistoryNode::printOtherModulesHistory(ParameterSetMap const& iPSM,
0241                                            ModuleToIdBranches const& iModules,
0242                                            std::vector<std::string> const& iFindMatch,
0243                                            std::ostream& oErrorLog) const {
0244   for (auto const& itH : *this) {
0245     //Get ParameterSet for process
0246     ParameterSetMap::const_iterator itFind = iPSM.find(itH.parameterSetID());
0247     if (itFind == iPSM.end()) {
0248       oErrorLog << "No ParameterSetID for " << itH.parameterSetID() << std::endl;
0249     } else {
0250       edm::ParameterSet processConfig(itFind->second.pset());
0251       std::vector<std::string> moduleStrings;
0252       //get all modules
0253       std::vector<std::string> modules = processConfig.getParameter<std::vector<std::string>>("@all_modules");
0254       for (auto& itM : modules) {
0255         //if we didn't already handle this from the branches
0256         if (iModules.end() == iModules.find(std::make_pair(itH.processName(), itM))) {
0257           std::string retValue(nonProducerComponent(itM, processConfig, itH.processName()));
0258           bool foundMatch = true;
0259           if (!iFindMatch.empty()) {
0260             for (auto const& stringToFind : iFindMatch) {
0261               if (retValue.find(stringToFind) == std::string::npos) {
0262                 foundMatch = false;
0263                 break;
0264               }
0265             }
0266           }
0267           if (foundMatch) {
0268             moduleStrings.push_back(std::move(retValue));
0269           }
0270         }
0271       }
0272       if (sort_) {
0273         std::sort(moduleStrings.begin(), moduleStrings.end());
0274       }
0275       std::copy(moduleStrings.begin(), moduleStrings.end(), std::ostream_iterator<std::string>(std::cout, "\n"));
0276     }
0277     itH.printOtherModulesHistory(iPSM, iModules, iFindMatch, oErrorLog);
0278   }
0279 }
0280 
0281 static void appendToSet(std::set<std::string>& iSet, std::vector<std::string> const& iFrom) {
0282   for (auto const& n : iFrom) {
0283     iSet.insert(n);
0284   }
0285 }
0286 
0287 static std::string topLevelPSet(std::string const& iName,
0288                                 edm::ParameterSet const& iProcessConfig,
0289                                 std::string const& iProcessName) {
0290   std::ostringstream result;
0291   edm::ParameterSet const& pset = iProcessConfig.getParameterSet(iName);
0292 
0293   result << "PSet: " << iName << " " << iProcessName << "\n"
0294          << " parameters: ";
0295   prettyPrint(result, pset, " ", " ");
0296   return result.str();
0297 }
0298 
0299 void HistoryNode::printTopLevelPSetsHistory(ParameterSetMap const& iPSM,
0300                                             std::vector<std::string> const& iFindMatch,
0301                                             std::ostream& oErrorLog) const {
0302   for (auto const& itH : *this) {
0303     //Get ParameterSet for process
0304     ParameterSetMap::const_iterator itFind = iPSM.find(itH.parameterSetID());
0305     if (itFind == iPSM.end()) {
0306       oErrorLog << "No ParameterSetID for " << itH.parameterSetID() << std::endl;
0307     } else {
0308       edm::ParameterSet processConfig(itFind->second.pset());
0309       //Need to get the names of PSets which are used by the framework (e.g. names of modules)
0310       std::set<std::string> namesToExclude;
0311       appendToSet(namesToExclude, processConfig.getParameter<std::vector<std::string>>("@all_modules"));
0312       appendToSet(namesToExclude, processConfig.getParameter<std::vector<std::string>>("@all_sources"));
0313       appendToSet(namesToExclude, processConfig.getParameter<std::vector<std::string>>("@all_loopers"));
0314       appendToSet(namesToExclude, processConfig.getParameter<std::vector<std::string>>("@all_esmodules"));
0315       appendToSet(namesToExclude, processConfig.getParameter<std::vector<std::string>>("@all_essources"));
0316       appendToSet(namesToExclude, processConfig.getParameter<std::vector<std::string>>("@all_esprefers"));
0317       if (processConfig.existsAs<std::vector<std::string>>("all_aliases")) {
0318         appendToSet(namesToExclude, processConfig.getParameter<std::vector<std::string>>("@all_aliases"));
0319       }
0320 
0321       std::vector<std::string> allNames{};
0322       processConfig.getParameterSetNames(allNames);
0323 
0324       std::vector<std::string> results;
0325       for (auto const& name : allNames) {
0326         if (name.empty() || '@' == name[0] || namesToExclude.find(name) != namesToExclude.end()) {
0327           continue;
0328         }
0329         std::string retValue = topLevelPSet(name, processConfig, itH.processName());
0330 
0331         bool foundMatch = true;
0332         if (!iFindMatch.empty()) {
0333           for (auto const& stringToFind : iFindMatch) {
0334             if (retValue.find(stringToFind) == std::string::npos) {
0335               foundMatch = false;
0336               break;
0337             }
0338           }
0339         }
0340         if (foundMatch) {
0341           results.push_back(std::move(retValue));
0342         }
0343       }
0344       if (sort_) {
0345         std::sort(results.begin(), results.end());
0346       }
0347       std::copy(results.begin(), results.end(), std::ostream_iterator<std::string>(std::cout, "\n"));
0348     }
0349     itH.printTopLevelPSetsHistory(iPSM, iFindMatch, oErrorLog);
0350   }
0351 }
0352 
0353 namespace {
0354   std::unique_ptr<TFile> makeTFileWithLookup(std::string const& filename) {
0355     // See if it is a logical file name.
0356     auto operate = edm::setupSiteLocalConfig();
0357     std::string override;
0358     std::vector<std::string> fileNames;
0359     fileNames.push_back(filename);
0360     edm::InputFileCatalog catalog(fileNames, override, true);
0361     if (catalog.fileNames(0)[0] == filename) {
0362       throw cms::Exception("FileNotFound", "RootFile::RootFile()")
0363           << "File " << filename << " was not found or could not be opened.\n";
0364     }
0365     // filename is a valid LFN.
0366     std::unique_ptr<TFile> result(TFile::Open(catalog.fileNames(0)[0].c_str()));
0367     if (!result.get()) {
0368       throw cms::Exception("FileNotFound", "RootFile::RootFile()")
0369           << "File " << fileNames[0] << " was not found or could not be opened.\n";
0370     }
0371     return result;
0372   }
0373 
0374   // Open the input file, returning the TFile object that represents it.
0375   // The returned unique_ptr will not be null. The argument must not be null.
0376   // We first try the file name as a PFN, so that the catalog and related
0377   // services are not loaded unless needed.
0378   std::unique_ptr<TFile> makeTFile(std::string const& filename) {
0379     gErrorIgnoreLevel = kFatal;
0380     std::unique_ptr<TFile> result(TFile::Open(filename.c_str()));
0381     gErrorIgnoreLevel = kError;
0382     if (!result.get()) {
0383       // Try again with catalog.
0384       return makeTFileWithLookup(filename);
0385     }
0386     return result;
0387   }
0388 }  // namespace
0389 
0390 static std::ostream& prettyPrint(std::ostream& os,
0391                                  edm::ParameterSetEntry const& psetEntry,
0392                                  std::string const& iIndent,
0393                                  std::string const& iIndentDelta) {
0394   char const* trackiness = (psetEntry.isTracked() ? "tracked" : "untracked");
0395   os << "PSet " << trackiness << " = (";
0396   prettyPrint(os, psetEntry.pset(), iIndent + iIndentDelta, iIndentDelta);
0397   os << ")";
0398   return os;
0399 }
0400 
0401 static std::ostream& prettyPrint(std::ostream& os,
0402                                  edm::VParameterSetEntry const& vpsetEntry,
0403                                  std::string const& iIndent,
0404                                  std::string const& iIndentDelta) {
0405   std::vector<edm::ParameterSet> const& vps = vpsetEntry.vpset();
0406   os << "VPSet " << (vpsetEntry.isTracked() ? "tracked" : "untracked") << " = ({" << std::endl;
0407   std::string newIndent = iIndent + iIndentDelta;
0408   std::string start;
0409   std::string const between(",\n");
0410   for (auto const& item : vps) {
0411     os << start << newIndent;
0412     prettyPrint(os, item, newIndent, iIndentDelta);
0413     start = between;
0414   }
0415   if (!vps.empty()) {
0416     os << std::endl;
0417   }
0418   os << iIndent << "})";
0419   return os;
0420 }
0421 
0422 static std::ostream& prettyPrint(std::ostream& oStream,
0423                                  edm::ParameterSet const& iPSet,
0424                                  std::string const& iIndent,
0425                                  std::string const& iIndentDelta) {
0426   std::string newIndent = iIndent + iIndentDelta;
0427 
0428   oStream << "{" << std::endl;
0429   for (auto const& item : iPSet.tbl()) {
0430     // indent a bit
0431     oStream << newIndent << item.first << ": " << item.second << std::endl;
0432   }
0433   for (auto const& item : iPSet.psetTable()) {
0434     // indent a bit
0435     edm::ParameterSetEntry const& pe = item.second;
0436     oStream << newIndent << item.first << ": ";
0437     prettyPrint(oStream, pe, iIndent, iIndentDelta);
0438     oStream << std::endl;
0439   }
0440   for (auto const& item : iPSet.vpsetTable()) {
0441     // indent a bit
0442     edm::VParameterSetEntry const& pe = item.second;
0443     oStream << newIndent << item.first << ": ";
0444     prettyPrint(oStream, pe, newIndent, iIndentDelta);
0445     oStream << std::endl;
0446   }
0447   oStream << iIndent << "}";
0448 
0449   return oStream;
0450 }
0451 
0452 class ProvenanceDumper {
0453 public:
0454   // It is illegal to call this constructor with a null pointer; a
0455   // legal C-style string is required.
0456   ProvenanceDumper(std::string const& filename,
0457                    bool showDependencies,
0458                    bool extendedAncestors,
0459                    bool extendedDescendants,
0460                    bool excludeESModules,
0461                    bool showAllModules,
0462                    bool showTopLevelPSets,
0463                    std::vector<std::string> const& findMatch,
0464                    bool dontPrintProducts,
0465                    std::string const& dumpPSetID,
0466                    int productIDEntry,
0467                    bool printHardwareResourcesDescription);
0468 
0469   ProvenanceDumper(ProvenanceDumper const&) = delete;             // Disallow copying and moving
0470   ProvenanceDumper& operator=(ProvenanceDumper const&) = delete;  // Disallow copying and moving
0471 
0472   // Write the provenenace information to the given stream.
0473   void dump();
0474   void printErrors(std::ostream& os);
0475   int exitCode() const;
0476 
0477 private:
0478   void addAncestors(edm::BranchID const& branchID,
0479                     std::set<edm::BranchID>& ancestorBranchIDs,
0480                     std::ostringstream& sout,
0481                     std::map<edm::BranchID, std::set<edm::ParentageID>>& perProductParentage) const;
0482 
0483   void addDescendants(edm::BranchID const& branchID,
0484                       std::set<edm::BranchID>& descendantBranchIDs,
0485                       std::ostringstream& sout,
0486                       std::map<edm::BranchID, std::set<edm::BranchID>>& parentToChildren) const;
0487 
0488   std::string filename_;
0489   edm::propagate_const<std::unique_ptr<TFile>> inputFile_;
0490   int exitCode_;
0491   std::stringstream errorLog_;
0492   int errorCount_;
0493   edm::ProductRegistry reg_;
0494   edm::ProcessConfigurationVector phc_;
0495   edm::ProcessHistoryVector phv_;
0496   ParameterSetMap psm_;
0497   HistoryNode historyGraph_;
0498   bool showDependencies_;
0499   bool extendedAncestors_;
0500   bool extendedDescendants_;
0501   bool excludeESModules_;
0502   bool showOtherModules_;
0503   bool productRegistryPresent_;
0504   bool showTopLevelPSets_;
0505   std::vector<std::string> findMatch_;
0506   bool dontPrintProducts_;
0507   std::string dumpPSetID_;
0508   int const productIDEntry_;
0509   bool const printHardwareResourcesDescription_;
0510 
0511   void work_();
0512   void dumpProcessHistory_();
0513   void dumpEventFilteringParameterSets_(TFile* file);
0514   void dumpEventFilteringParameterSets(edm::EventSelectionIDVector const& ids);
0515   void dumpParameterSetForID_(edm::ParameterSetID const& id);
0516   std::optional<std::tuple<edm::BranchIDListHelper, std::vector<edm::ProcessIndex>>> makeBranchIDListHelper();
0517 };
0518 
0519 ProvenanceDumper::ProvenanceDumper(std::string const& filename,
0520                                    bool showDependencies,
0521                                    bool extendedAncestors,
0522                                    bool extendedDescendants,
0523                                    bool excludeESModules,
0524                                    bool showOtherModules,
0525                                    bool showTopLevelPSets,
0526                                    std::vector<std::string> const& findMatch,
0527                                    bool dontPrintProducts,
0528                                    std::string const& dumpPSetID,
0529                                    int productIDEntry,
0530                                    bool printHardwareResourcesDescription)
0531     : filename_(filename),
0532       inputFile_(makeTFile(filename)),
0533       exitCode_(0),
0534       errorLog_(),
0535       errorCount_(0),
0536       showDependencies_(showDependencies),
0537       extendedAncestors_(extendedAncestors),
0538       extendedDescendants_(extendedDescendants),
0539       excludeESModules_(excludeESModules),
0540       showOtherModules_(showOtherModules),
0541       productRegistryPresent_(true),
0542       showTopLevelPSets_(showTopLevelPSets),
0543       findMatch_(findMatch),
0544       dontPrintProducts_(dontPrintProducts),
0545       dumpPSetID_(dumpPSetID),
0546       productIDEntry_(productIDEntry),
0547       printHardwareResourcesDescription_(printHardwareResourcesDescription) {}
0548 
0549 void ProvenanceDumper::dump() { work_(); }
0550 
0551 void ProvenanceDumper::printErrors(std::ostream& os) {
0552   if (errorCount_ > 0)
0553     os << errorLog_.str() << std::endl;
0554 }
0555 
0556 int ProvenanceDumper::exitCode() const { return exitCode_; }
0557 
0558 void ProvenanceDumper::dumpEventFilteringParameterSets(edm::EventSelectionIDVector const& ids) {
0559   edm::EventSelectionIDVector::size_type num_ids = ids.size();
0560   if (num_ids == 0) {
0561     std::cout << "No event filtering information is available.\n";
0562     std::cout << "------------------------------\n";
0563   } else {
0564     std::cout << "Event filtering information for " << num_ids << " processing steps is available.\n"
0565               << "The ParameterSets will be printed out, "
0566               << "with the oldest printed first.\n";
0567     for (edm::EventSelectionIDVector::size_type i = 0; i != num_ids; ++i) {
0568       dumpParameterSetForID_(ids[i]);
0569     }
0570   }
0571 }
0572 
0573 void ProvenanceDumper::dumpEventFilteringParameterSets_(TFile* file) {
0574   TTree* history = dynamic_cast<TTree*>(file->Get(edm::poolNames::eventHistoryTreeName().c_str()));
0575   if (history != nullptr) {
0576     edm::History h;
0577     edm::History* ph = &h;
0578 
0579     history->SetBranchAddress(edm::poolNames::eventHistoryBranchName().c_str(), &ph);
0580     if (history->GetEntry(0) <= 0) {
0581       std::cout << "No event filtering information is available; the event history tree has no entries\n";
0582     } else {
0583       dumpEventFilteringParameterSets(h.eventSelectionIDs());
0584     }
0585   } else {
0586     TTree* events = dynamic_cast<TTree*>(file->Get(edm::poolNames::eventTreeName().c_str()));
0587     assert(events != nullptr);
0588     TBranch* eventSelectionsBranch = events->GetBranch(edm::poolNames::eventSelectionsBranchName().c_str());
0589     if (eventSelectionsBranch == nullptr)
0590       return;
0591     edm::EventSelectionIDVector ids;
0592     edm::EventSelectionIDVector* pids = &ids;
0593     eventSelectionsBranch->SetAddress(&pids);
0594     if (eventSelectionsBranch->GetEntry(0) <= 0) {
0595       std::cout << "No event filtering information is available; the event selections branch has no entries\n";
0596     } else {
0597       dumpEventFilteringParameterSets(ids);
0598     }
0599   }
0600 }
0601 
0602 void ProvenanceDumper::dumpParameterSetForID_(edm::ParameterSetID const& id) {
0603   std::cout << "ParameterSetID: " << id << '\n';
0604   if (id.isValid()) {
0605     ParameterSetMap::const_iterator i = psm_.find(id);
0606     if (i == psm_.end()) {
0607       std::cout << "We are unable to find the corresponding ParameterSet\n";
0608       edm::ParameterSet empty;
0609       empty.registerIt();
0610       if (id == empty.id()) {
0611         std::cout << "But it would have been empty anyway\n";
0612       }
0613     } else {
0614       edm::ParameterSet ps(i->second.pset());
0615       prettyPrint(std::cout, ps, " ", " ");
0616       std::cout << '\n';
0617     }
0618   } else {
0619     std::cout << "This ID is not valid\n";
0620   }
0621   std::cout << "     -------------------------\n";
0622 }
0623 
0624 void ProvenanceDumper::dumpProcessHistory_() {
0625   std::cout << "Processing History:" << std::endl;
0626   std::map<edm::ProcessConfigurationID, unsigned int> simpleIDs;
0627   for (auto const& ph : phv_) {
0628     //loop over the history entries looking for matches
0629     HistoryNode* parent = &historyGraph_;
0630     for (auto const& pc : ph) {
0631       if (parent->size() == 0) {
0632         unsigned int id = simpleIDs[pc.id()];
0633         if (0 == id) {
0634           id = 1;
0635           simpleIDs[pc.id()] = id;
0636         }
0637         parent->addChild(HistoryNode(pc, id, printHardwareResourcesDescription_));
0638         parent = parent->lastChildAddress();
0639       } else {
0640         //see if this is unique
0641         bool isUnique = true;
0642         for (auto& child : *parent) {
0643           if (child.configurationID() == pc.id()) {
0644             isUnique = false;
0645             parent = &child;
0646             break;
0647           }
0648         }
0649         if (isUnique) {
0650           simpleIDs[pc.id()] = parent->size() + 1;
0651           parent->addChild(HistoryNode(pc, simpleIDs[pc.id()], printHardwareResourcesDescription_));
0652           parent = parent->lastChildAddress();
0653         }
0654       }
0655     }
0656   }
0657   historyGraph_.printHistory();
0658 }
0659 
0660 std::optional<std::tuple<edm::BranchIDListHelper, std::vector<edm::ProcessIndex>>>
0661 ProvenanceDumper::makeBranchIDListHelper() {
0662   // BranchID-to-ProductID mapping disabled
0663   if (productIDEntry_ < 0) {
0664     return {};
0665   }
0666 
0667   TTree* metaTree = dynamic_cast<TTree*>(inputFile_->Get(edm::poolNames::metaDataTreeName().c_str()));
0668   if (nullptr == metaTree) {
0669     //std::cerr << "Did not find " << edm::poolNames::metaDataTreeName() << " tree" << std::endl;
0670     return {};
0671   }
0672 
0673   TBranch* branchIDListsBranch = metaTree->GetBranch(edm::poolNames::branchIDListBranchName().c_str());
0674   if (nullptr == branchIDListsBranch) {
0675     /*
0676     std::cerr << "Did not find " << edm::poolNames::branchIDListBranchName() << " from "
0677               << edm::poolNames::metaDataTreeName() << " tree" << std::endl;
0678     */
0679     return {};
0680   }
0681 
0682   edm::BranchIDLists branchIDLists;
0683   edm::BranchIDLists* branchIDListsPtr = &branchIDLists;
0684   branchIDListsBranch->SetAddress(&branchIDListsPtr);
0685   if (branchIDListsBranch->GetEntry(0) <= 0) {
0686     //std::cerr << "Failed to read an entry from " << edm::poolNames::branchIDListBranchName() << std::endl;
0687     return {};
0688   }
0689 
0690   edm::BranchIDListHelper branchIDListHelper;
0691   branchIDListHelper.updateFromInput(branchIDLists);
0692 
0693   TTree* events = dynamic_cast<TTree*>(inputFile_->Get(edm::poolNames::eventTreeName().c_str()));
0694   assert(events != nullptr);
0695   TBranch* branchListIndexesBranch = events->GetBranch(edm::poolNames::branchListIndexesBranchName().c_str());
0696   if (nullptr == branchListIndexesBranch) {
0697     /*
0698     std::cerr << "Did not find " << edm::poolNames::branchListIndexesBranchName() << " from "
0699               << edm::poolNames::eventTreeName() << " tree" << std::endl;
0700     */
0701     return {};
0702   }
0703   edm::BranchListIndexes branchListIndexes;
0704   edm::BranchListIndexes* pbranchListIndexes = &branchListIndexes;
0705   branchListIndexesBranch->SetAddress(&pbranchListIndexes);
0706   if (branchListIndexesBranch->GetEntry(productIDEntry_) <= 0 or branchListIndexes.empty()) {
0707     /*
0708     std::cerr << "Failed to read entry from " << edm::poolNames::branchListIndexesBranchName() << ", or it is empty"
0709               << std::endl;
0710     */
0711     return {};
0712   }
0713 
0714   if (not branchIDListHelper.fixBranchListIndexes(branchListIndexes)) {
0715     //std::cerr << "Call to branchIDListHelper.fixBranchListIndexes() failed" << std::endl;
0716     return {};
0717   }
0718 
0719   // Fill in helper map for Branch to ProductID mapping
0720   auto branchListIndexToProcessIndex = edm::makeBranchListIndexToProcessIndex(branchListIndexes);
0721 
0722   return std::tuple(std::move(branchIDListHelper), std::move(branchListIndexToProcessIndex));
0723 }
0724 
0725 void ProvenanceDumper::work_() {
0726   TTree* meta = dynamic_cast<TTree*>(inputFile_->Get(edm::poolNames::metaDataTreeName().c_str()));
0727   assert(nullptr != meta);
0728 
0729   edm::ProductRegistry* pReg = &reg_;
0730   if (meta->FindBranch(edm::poolNames::productDescriptionBranchName().c_str()) != nullptr) {
0731     meta->SetBranchAddress(edm::poolNames::productDescriptionBranchName().c_str(), &pReg);
0732   } else {
0733     productRegistryPresent_ = false;
0734   }
0735 
0736   ParameterSetMap* pPsm = &psm_;
0737   if (meta->FindBranch(edm::poolNames::parameterSetMapBranchName().c_str()) != nullptr) {
0738     meta->SetBranchAddress(edm::poolNames::parameterSetMapBranchName().c_str(), &pPsm);
0739   } else {
0740     TTree* psetTree = dynamic_cast<TTree*>(inputFile_->Get(edm::poolNames::parameterSetsTreeName().c_str()));
0741     assert(nullptr != psetTree);
0742     typedef std::pair<edm::ParameterSetID, edm::ParameterSetBlob> IdToBlobs;
0743     IdToBlobs idToBlob;
0744     IdToBlobs* pIdToBlob = &idToBlob;
0745     psetTree->SetBranchAddress(edm::poolNames::idToParameterSetBlobsBranchName().c_str(), &pIdToBlob);
0746     for (long long i = 0; i != psetTree->GetEntries(); ++i) {
0747       psetTree->GetEntry(i);
0748       psm_.insert(idToBlob);
0749     }
0750   }
0751 
0752   edm::ProcessHistoryVector* pPhv = &phv_;
0753   if (meta->FindBranch(edm::poolNames::processHistoryBranchName().c_str()) != nullptr) {
0754     meta->SetBranchAddress(edm::poolNames::processHistoryBranchName().c_str(), &pPhv);
0755   }
0756 
0757   edm::ProcessHistoryMap phm;
0758   edm::ProcessHistoryMap* pPhm = &phm;
0759   if (meta->FindBranch(edm::poolNames::processHistoryMapBranchName().c_str()) != nullptr) {
0760     meta->SetBranchAddress(edm::poolNames::processHistoryMapBranchName().c_str(), &pPhm);
0761   }
0762 
0763   if (meta->FindBranch(edm::poolNames::moduleDescriptionMapBranchName().c_str()) != nullptr) {
0764     if (meta->GetBranch(edm::poolNames::moduleDescriptionMapBranchName().c_str())->GetSplitLevel() != 0) {
0765       meta->SetBranchStatus((edm::poolNames::moduleDescriptionMapBranchName() + ".*").c_str(), false);
0766     } else {
0767       meta->SetBranchStatus(edm::poolNames::moduleDescriptionMapBranchName().c_str(), false);
0768     }
0769   }
0770 
0771   meta->GetEntry(0);
0772   assert(nullptr != pReg);
0773 
0774   edm::pset::Registry& psetRegistry = *edm::pset::Registry::instance();
0775   for (auto const& item : psm_) {
0776     edm::ParameterSet pset(item.second.pset());
0777     pset.setID(item.first);
0778     psetRegistry.insertMapped(pset);
0779   }
0780 
0781   if (!phv_.empty()) {
0782     for (auto const& history : phv_) {
0783       for (auto const& process : history) {
0784         phc_.push_back(process);
0785       }
0786     }
0787     edm::sort_all(phc_);
0788     phc_.erase(std::unique(phc_.begin(), phc_.end()), phc_.end());
0789 
0790   }
0791   // backward compatibility
0792   else if (!phm.empty()) {
0793     for (auto const& history : phm) {
0794       phv_.push_back(history.second);
0795       for (auto const& process : history.second) {
0796         phc_.push_back(process);
0797       }
0798     }
0799     edm::sort_all(phc_);
0800     phc_.erase(std::unique(phc_.begin(), phc_.end()), phc_.end());
0801   }
0802 
0803   if (!dumpPSetID_.empty()) {
0804     edm::ParameterSetID psetID;
0805     try {
0806       psetID = edm::ParameterSetID(dumpPSetID_);
0807     } catch (cms::Exception const& x) {
0808       throw cms::Exception("Command Line Argument")
0809           << "Illegal ParameterSetID string. It should contain 32 hexadecimal characters";
0810     }
0811     dumpParameterSetForID_(psetID);
0812     return;
0813   }
0814 
0815   // Helper to map BranchID to ProductID (metadata tree needed also for parentage information)
0816   auto branchIDListHelperAndToProcessIndex = makeBranchIDListHelper();
0817 
0818   //Prepare the parentage information if requested
0819   std::map<edm::BranchID, std::set<edm::ParentageID>> perProductParentage;
0820 
0821   if (showDependencies_ || extendedAncestors_ || extendedDescendants_) {
0822     TTree* parentageTree = dynamic_cast<TTree*>(inputFile_->Get(edm::poolNames::parentageTreeName().c_str()));
0823     if (nullptr == parentageTree) {
0824       std::cerr << "ERROR, no Parentage tree available so cannot show dependencies, ancestors, or descendants.\n";
0825       std::cerr << "Possibly this is not a standard EDM format file. For example, dependency, ancestor, and\n";
0826       std::cerr << "descendant options to edmProvDump will not work with nanoAOD format files.\n\n";
0827       showDependencies_ = false;
0828       extendedAncestors_ = false;
0829       extendedDescendants_ = false;
0830     } else {
0831       edm::ParentageRegistry& registry = *edm::ParentageRegistry::instance();
0832 
0833       std::vector<edm::ParentageID> orderedParentageIDs;
0834       orderedParentageIDs.reserve(parentageTree->GetEntries());
0835       for (Long64_t i = 0, numEntries = parentageTree->GetEntries(); i < numEntries; ++i) {
0836         edm::Parentage parentageBuffer;
0837         edm::Parentage* pParentageBuffer = &parentageBuffer;
0838         parentageTree->SetBranchAddress(edm::poolNames::parentageBranchName().c_str(), &pParentageBuffer);
0839         parentageTree->GetEntry(i);
0840         registry.insertMapped(parentageBuffer);
0841         orderedParentageIDs.push_back(parentageBuffer.id());
0842       }
0843       parentageTree->SetBranchAddress(edm::poolNames::parentageBranchName().c_str(), nullptr);
0844 
0845       TTree* eventMetaTree =
0846           dynamic_cast<TTree*>(inputFile_->Get(edm::BranchTypeToMetaDataTreeName(edm::InEvent).c_str()));
0847       if (nullptr == eventMetaTree) {
0848         eventMetaTree = dynamic_cast<TTree*>(inputFile_->Get(edm::BranchTypeToProductTreeName(edm::InEvent).c_str()));
0849       }
0850       if (nullptr == eventMetaTree) {
0851         std::cerr << "ERROR, no '" << edm::BranchTypeToProductTreeName(edm::InEvent)
0852                   << "' Tree in file so can not show dependencies\n";
0853         showDependencies_ = false;
0854         extendedAncestors_ = false;
0855         extendedDescendants_ = false;
0856       } else {
0857         TBranch* storedProvBranch =
0858             eventMetaTree->GetBranch(edm::BranchTypeToProductProvenanceBranchName(edm::InEvent).c_str());
0859 
0860         if (nullptr != storedProvBranch) {
0861           std::vector<edm::StoredProductProvenance> info;
0862           std::vector<edm::StoredProductProvenance>* pInfo = &info;
0863           storedProvBranch->SetAddress(&pInfo);
0864           for (Long64_t i = 0, numEntries = eventMetaTree->GetEntries(); i < numEntries; ++i) {
0865             storedProvBranch->GetEntry(i);
0866             for (auto const& item : info) {
0867               edm::BranchID bid(item.branchID_);
0868               perProductParentage[bid].insert(orderedParentageIDs.at(item.parentageIDIndex_));
0869             }
0870           }
0871         } else {
0872           //backwards compatible check
0873           TBranch* productProvBranch =
0874               eventMetaTree->GetBranch(edm::BranchTypeToBranchEntryInfoBranchName(edm::InEvent).c_str());
0875           if (nullptr != productProvBranch) {
0876             std::vector<edm::ProductProvenance> info;
0877             std::vector<edm::ProductProvenance>* pInfo = &info;
0878             productProvBranch->SetAddress(&pInfo);
0879             for (Long64_t i = 0, numEntries = eventMetaTree->GetEntries(); i < numEntries; ++i) {
0880               productProvBranch->GetEntry(i);
0881               for (auto const& item : info) {
0882                 perProductParentage[item.branchID()].insert(item.parentageID());
0883               }
0884             }
0885           } else {
0886             std::cerr << " ERROR, could not find provenance information so can not show dependencies\n";
0887             showDependencies_ = false;
0888             extendedAncestors_ = false;
0889             extendedDescendants_ = false;
0890           }
0891         }
0892       }
0893     }
0894   }
0895 
0896   std::map<edm::BranchID, std::set<edm::BranchID>> parentToChildren;
0897   edm::ParentageRegistry& registry = *edm::ParentageRegistry::instance();
0898 
0899   if (extendedDescendants_) {
0900     for (auto const& itParentageSet : perProductParentage) {
0901       edm::BranchID childBranchID = itParentageSet.first;
0902       for (auto const& itParentageID : itParentageSet.second) {
0903         edm::Parentage const* parentage = registry.getMapped(itParentageID);
0904         if (nullptr != parentage) {
0905           for (auto const& branch : parentage->parents()) {
0906             parentToChildren[branch].insert(childBranchID);
0907           }
0908         } else {
0909           std::cerr << "  ERROR:parentage info not in registry ParentageID=" << itParentageID << std::endl;
0910         }
0911       }
0912     }
0913   }
0914 
0915   dumpEventFilteringParameterSets_(inputFile_.get());
0916 
0917   dumpProcessHistory_();
0918 
0919   if (productRegistryPresent_) {
0920     std::cout << "---------Producers with data in file---------" << std::endl;
0921   }
0922 
0923   //using edm::ParameterSetID as the key does not work
0924   //   typedef std::map<edm::ParameterSetID, std::vector<edm::ProductDescription> > IdToBranches
0925   ModuleToIdBranches moduleToIdBranches;
0926   //IdToBranches idToBranches;
0927 
0928   std::map<edm::BranchID, std::string> branchIDToBranchName;
0929 
0930   for (auto const& processConfig : phc_) {
0931     edm::ParameterSet const* processParameterSet =
0932         edm::pset::Registry::instance()->getMapped(processConfig.parameterSetID());
0933     if (nullptr == processParameterSet || processParameterSet->empty()) {
0934       continue;
0935     }
0936     for (auto& item : reg_.productListUpdator()) {
0937       auto& product = item.second;
0938       if (product.processName() != processConfig.processName()) {
0939         continue;
0940       }
0941       //force it to rebuild the branch name
0942       product.init();
0943       setIsMergeable(product);
0944 
0945       if (showDependencies_ || extendedAncestors_ || extendedDescendants_) {
0946         branchIDToBranchName[product.branchID()] = product.branchName();
0947       }
0948       /*
0949         std::cout << product.branchName()
0950         << " id " << product.productID() << std::endl;
0951       */
0952       std::string moduleLabel = product.moduleLabel();
0953       if (moduleLabel == source) {
0954         moduleLabel = input;
0955       } else if (moduleLabel == triggerResults) {
0956         moduleLabel = triggerPaths;
0957       }
0958 
0959       std::stringstream s;
0960 
0961       if (processParameterSet->existsAs<edm::ParameterSet>(moduleLabel)) {
0962         edm::ParameterSet const& moduleParameterSet = processParameterSet->getParameterSet(moduleLabel);
0963         if (!moduleParameterSet.isRegistered()) {
0964           edm::ParameterSet moduleParameterSetCopy = processParameterSet->getParameterSet(moduleLabel);
0965           moduleParameterSetCopy.registerIt();
0966           s << moduleParameterSetCopy.id();
0967         } else {
0968           s << moduleParameterSet.id();
0969         }
0970         moduleToIdBranches[std::make_pair(product.processName(), product.moduleLabel())][s.str()].push_back(product);
0971       }
0972     }
0973   }
0974 
0975   for (auto const& item : moduleToIdBranches) {
0976     std::ostringstream sout;
0977     sout << "Module: " << item.first.second << " " << item.first.first << std::endl;
0978     std::set<edm::BranchID> allBranchIDsForLabelAndProcess;
0979     IdToBranches const& idToBranches = item.second;
0980     for (auto const& idBranch : idToBranches) {
0981       sout << " PSet id:" << idBranch.first << std::endl;
0982       if (!dontPrintProducts_) {
0983         sout << " products: {" << std::endl;
0984       }
0985       std::set<edm::BranchID> branchIDs;
0986       for (auto const& branch : idBranch.second) {
0987         if (!dontPrintProducts_) {
0988           sout << "  " << branch.branchName();
0989           edm::ProductID id;
0990           if (branchIDListHelperAndToProcessIndex) {
0991             sout << " ProductID "
0992                  << edm::branchIDToProductID(branch.branchID(),
0993                                              std::get<0>(*branchIDListHelperAndToProcessIndex),
0994                                              std::get<1>(*branchIDListHelperAndToProcessIndex));
0995           } else {
0996             sout << " BranchID " << branch.branchID();
0997           }
0998           sout << std::endl;
0999         }
1000         branchIDs.insert(branch.branchID());
1001         allBranchIDsForLabelAndProcess.insert(branch.branchID());
1002       }
1003       sout << " }" << std::endl;
1004       edm::ParameterSetID psid(idBranch.first);
1005       ParameterSetMap::const_iterator itpsm = psm_.find(psid);
1006       if (psm_.end() == itpsm) {
1007         ++errorCount_;
1008         errorLog_ << "No ParameterSetID for " << psid << std::endl;
1009         exitCode_ = 1;
1010       } else {
1011         sout << " parameters: ";
1012         prettyPrint(sout, edm::ParameterSet((*itpsm).second.pset()), " ", " ");
1013         sout << std::endl;
1014       }
1015       if (showDependencies_) {
1016         sout << " dependencies: {" << std::endl;
1017         std::set<edm::ParentageID> parentageIDs;
1018         for (auto const& branch : branchIDs) {
1019           //Save these BranchIDs
1020           std::set<edm::ParentageID> const& temp = perProductParentage[branch];
1021           parentageIDs.insert(temp.begin(), temp.end());
1022         }
1023         for (auto const& parentID : parentageIDs) {
1024           edm::Parentage const* parentage = registry.getMapped(parentID);
1025           if (nullptr != parentage) {
1026             for (auto const& branch : parentage->parents()) {
1027               sout << "  " << branchIDToBranchName[branch] << std::endl;
1028             }
1029           } else {
1030             sout << "  ERROR:parentage info not in registry ParentageID=" << parentID << std::endl;
1031           }
1032         }
1033         if (parentageIDs.empty()) {
1034           sout << "  no dependencies recorded (event may not contain data from this module)" << std::endl;
1035         }
1036         sout << " }" << std::endl;
1037       }
1038     }  // end loop over PSetIDs
1039     if (extendedAncestors_) {
1040       sout << " extendedAncestors: {" << std::endl;
1041       std::set<edm::BranchID> ancestorBranchIDs;
1042       for (auto const& branchID : allBranchIDsForLabelAndProcess) {
1043         addAncestors(branchID, ancestorBranchIDs, sout, perProductParentage);
1044       }
1045       for (auto const& ancestorBranchID : ancestorBranchIDs) {
1046         sout << "  " << branchIDToBranchName[ancestorBranchID] << "\n";
1047       }
1048       sout << " }" << std::endl;
1049     }
1050 
1051     if (extendedDescendants_) {
1052       sout << " extendedDescendants: {" << std::endl;
1053       std::set<edm::BranchID> descendantBranchIDs;
1054       for (auto const& branchID : allBranchIDsForLabelAndProcess) {
1055         addDescendants(branchID, descendantBranchIDs, sout, parentToChildren);
1056       }
1057       for (auto const& descendantBranchID : descendantBranchIDs) {
1058         sout << "  " << branchIDToBranchName[descendantBranchID] << "\n";
1059       }
1060       sout << " }" << std::endl;
1061     }
1062     bool foundMatch = true;
1063     if (!findMatch_.empty()) {
1064       for (auto const& stringToFind : findMatch_) {
1065         if (sout.str().find(stringToFind) == std::string::npos) {
1066           foundMatch = false;
1067           break;
1068         }
1069       }
1070     }
1071     if (foundMatch) {
1072       std::cout << sout.str() << std::endl;
1073     }
1074   }  // end loop over module label/process
1075 
1076   if (productRegistryPresent_ && showOtherModules_) {
1077     std::cout << "---------Other Modules---------" << std::endl;
1078     historyGraph_.printOtherModulesHistory(psm_, moduleToIdBranches, findMatch_, errorLog_);
1079   } else if (!productRegistryPresent_) {
1080     std::cout << "---------All Modules---------" << std::endl;
1081     historyGraph_.printOtherModulesHistory(psm_, moduleToIdBranches, findMatch_, errorLog_);
1082   }
1083 
1084   if (!excludeESModules_) {
1085     std::cout << "---------EventSetup---------" << std::endl;
1086     historyGraph_.printEventSetupHistory(psm_, findMatch_, errorLog_);
1087   }
1088 
1089   if (showTopLevelPSets_) {
1090     std::cout << "---------Top Level PSets---------" << std::endl;
1091     historyGraph_.printTopLevelPSetsHistory(psm_, findMatch_, errorLog_);
1092   }
1093   if (errorCount_ != 0) {
1094     exitCode_ = 1;
1095   }
1096 }
1097 
1098 void ProvenanceDumper::addAncestors(edm::BranchID const& branchID,
1099                                     std::set<edm::BranchID>& ancestorBranchIDs,
1100                                     std::ostringstream& sout,
1101                                     std::map<edm::BranchID, std::set<edm::ParentageID>>& perProductParentage) const {
1102   edm::ParentageRegistry& registry = *edm::ParentageRegistry::instance();
1103 
1104   std::set<edm::ParentageID> const& parentIDs = perProductParentage[branchID];
1105   for (auto const& parentageID : parentIDs) {
1106     edm::Parentage const* parentage = registry.getMapped(parentageID);
1107     if (nullptr != parentage) {
1108       for (auto const& branch : parentage->parents()) {
1109         if (ancestorBranchIDs.insert(branch).second) {
1110           addAncestors(branch, ancestorBranchIDs, sout, perProductParentage);
1111         }
1112       }
1113     } else {
1114       sout << "  ERROR:parentage info not in registry ParentageID=" << parentageID << std::endl;
1115     }
1116   }
1117 }
1118 
1119 void ProvenanceDumper::addDescendants(edm::BranchID const& branchID,
1120                                       std::set<edm::BranchID>& descendantBranchIDs,
1121                                       std::ostringstream& sout,
1122                                       std::map<edm::BranchID, std::set<edm::BranchID>>& parentToChildren) const {
1123   for (auto const& childBranchID : parentToChildren[branchID]) {
1124     if (descendantBranchIDs.insert(childBranchID).second) {
1125       addDescendants(childBranchID, descendantBranchIDs, sout, parentToChildren);
1126     }
1127   }
1128 }
1129 
1130 static char const* const kSortOpt = "sort";
1131 static char const* const kSortCommandOpt = "sort,s";
1132 static char const* const kDependenciesOpt = "dependencies";
1133 static char const* const kDependenciesCommandOpt = "dependencies,d";
1134 static char const* const kExtendedAncestorsOpt = "extendedAncestors";
1135 static char const* const kExtendedAncestorsCommandOpt = "extendedAncestors,x";
1136 static char const* const kExtendedDescendantsOpt = "extendedDescendants";
1137 static char const* const kExtendedDescendantsCommandOpt = "extendedDescendants,c";
1138 static char const* const kExcludeESModulesOpt = "excludeESModules";
1139 static char const* const kExcludeESModulesCommandOpt = "excludeESModules,e";
1140 static char const* const kShowAllModulesOpt = "showAllModules";
1141 static char const* const kShowAllModulesCommandOpt = "showAllModules,a";
1142 static char const* const kFindMatchOpt = "findMatch";
1143 static char const* const kFindMatchCommandOpt = "findMatch,f";
1144 static char const* const kDontPrintProductsOpt = "dontPrintProducts";
1145 static char const* const kDontPrintProductsCommandOpt = "dontPrintProducts,p";
1146 static char const* const kShowTopLevelPSetsOpt = "showTopLevelPSets";
1147 static char const* const kShowTopLevelPSetsCommandOpt = "showTopLevelPSets,t";
1148 static char const* const kHelpOpt = "help";
1149 static char const* const kHelpCommandOpt = "help,h";
1150 static char const* const kFileNameOpt = "input-file";
1151 static char const* const kDumpPSetIDOpt = "dumpPSetID";
1152 static char const* const kDumpPSetIDCommandOpt = "dumpPSetID,i";
1153 static char const* const kProductIDEntryOpt = "productIDEntry";
1154 static char const* const kHardwareOpt = "hardware";
1155 
1156 int main(int argc, char* argv[]) {
1157   using namespace boost::program_options;
1158 
1159   std::string descString(argv[0]);
1160   descString += " [options] <filename>";
1161   descString += "\nAllowed options";
1162   options_description desc(descString);
1163 
1164   // clang-format off
1165   desc.add_options()(kHelpCommandOpt, "show help message")(kSortCommandOpt, "alphabetially sort EventSetup components")(
1166       kDependenciesCommandOpt, "print what data each EDProducer is directly dependent upon")(
1167       kExtendedAncestorsCommandOpt, "print what data each EDProducer is dependent upon including indirect dependences")(
1168       kExtendedDescendantsCommandOpt,
1169       "print what data depends on the data each EDProducer produces including indirect dependences")(
1170       kExcludeESModulesCommandOpt, "do not print ES module information")(
1171       kShowAllModulesCommandOpt, "show all modules (not just those that created data in the file)")(
1172       kShowTopLevelPSetsCommandOpt, "show all top level PSets")(
1173       kFindMatchCommandOpt,
1174       boost::program_options::value<std::vector<std::string>>(),
1175       "show only modules whose information contains the matching string (or all the matching strings, this option can "
1176       "be repeated with different strings)")(kDontPrintProductsCommandOpt, "do not print products produced by module")(
1177       kDumpPSetIDCommandOpt,
1178       value<std::string>(),
1179       "print the parameter set associated with the parameter set ID string (and print nothing else)")(
1180       kProductIDEntryOpt,
1181       value<int>(),
1182       "show ProductID instead of BranchID using the specified entry in the Events tree")(
1183       kHardwareOpt,
1184       "include hardware provenance");
1185   // clang-format on
1186 
1187   //we don't want users to see these in the help messages since this
1188   // name only exists since the parser needs it
1189   options_description hidden;
1190   hidden.add_options()(kFileNameOpt, value<std::string>(), "file name");
1191 
1192   //full list of options for the parser
1193   options_description cmdline_options;
1194   cmdline_options.add(desc).add(hidden);
1195 
1196   positional_options_description p;
1197   p.add(kFileNameOpt, -1);
1198 
1199   variables_map vm;
1200   try {
1201     store(command_line_parser(argc, argv).options(cmdline_options).positional(p).run(), vm);
1202     notify(vm);
1203   } catch (error const& iException) {
1204     std::cerr << iException.what();
1205     return 1;
1206   }
1207 
1208   if (vm.count(kHelpOpt)) {
1209     std::cout << desc << std::endl;
1210     return 0;
1211   }
1212 
1213   if (vm.count(kSortOpt)) {
1214     HistoryNode::sort_ = true;
1215   }
1216 
1217   bool showDependencies = false;
1218   if (vm.count(kDependenciesOpt)) {
1219     showDependencies = true;
1220   }
1221 
1222   bool extendedAncestors = false;
1223   if (vm.count(kExtendedAncestorsOpt)) {
1224     extendedAncestors = true;
1225   }
1226 
1227   bool extendedDescendants = false;
1228   if (vm.count(kExtendedDescendantsOpt)) {
1229     extendedDescendants = true;
1230   }
1231 
1232   bool excludeESModules = false;
1233   if (vm.count(kExcludeESModulesOpt)) {
1234     excludeESModules = true;
1235   }
1236 
1237   bool showAllModules = false;
1238   if (vm.count(kShowAllModulesOpt)) {
1239     showAllModules = true;
1240   }
1241 
1242   bool showTopLevelPSets = false;
1243   if (vm.count(kShowTopLevelPSetsOpt)) {
1244     showTopLevelPSets = true;
1245   }
1246 
1247   std::string fileName;
1248   if (vm.count(kFileNameOpt)) {
1249     try {
1250       fileName = vm[kFileNameOpt].as<std::string>();
1251     } catch (boost::bad_any_cast const& e) {
1252       std::cout << e.what() << std::endl;
1253       return 2;
1254     }
1255   } else {
1256     std::cout << "Data file not specified." << std::endl;
1257     std::cout << desc << std::endl;
1258     return 2;
1259   }
1260 
1261   std::string dumpPSetID;
1262   if (vm.count(kDumpPSetIDOpt)) {
1263     try {
1264       dumpPSetID = vm[kDumpPSetIDOpt].as<std::string>();
1265     } catch (boost::bad_any_cast const& e) {
1266       std::cout << e.what() << std::endl;
1267       return 2;
1268     }
1269   }
1270 
1271   std::vector<std::string> findMatch;
1272   if (vm.count(kFindMatchOpt)) {
1273     try {
1274       findMatch = vm[kFindMatchOpt].as<std::vector<std::string>>();
1275     } catch (boost::bad_any_cast const& e) {
1276       std::cout << e.what() << std::endl;
1277       return 2;
1278     }
1279   }
1280 
1281   bool dontPrintProducts = false;
1282   if (vm.count(kDontPrintProductsOpt)) {
1283     dontPrintProducts = true;
1284   }
1285 
1286   int productIDEntry = -1;
1287   if (vm.count(kProductIDEntryOpt)) {
1288     try {
1289       productIDEntry = vm[kProductIDEntryOpt].as<int>();
1290     } catch (boost::bad_any_cast const& e) {
1291       std::cout << e.what() << std::endl;
1292       return 2;
1293     }
1294   }
1295 
1296   bool printHardwareResourcesDescription = false;
1297   if (vm.count(kHardwareOpt)) {
1298     printHardwareResourcesDescription = true;
1299   }
1300 
1301   //silence ROOT warnings about missing dictionaries
1302   gErrorIgnoreLevel = kError;
1303 
1304   ProvenanceDumper dumper(fileName,
1305                           showDependencies,
1306                           extendedAncestors,
1307                           extendedDescendants,
1308                           excludeESModules,
1309                           showAllModules,
1310                           showTopLevelPSets,
1311                           findMatch,
1312                           dontPrintProducts,
1313                           dumpPSetID,
1314                           productIDEntry,
1315                           printHardwareResourcesDescription);
1316   int exitCode(0);
1317   try {
1318     dumper.dump();
1319     exitCode = dumper.exitCode();
1320   } catch (cms::Exception const& x) {
1321     std::cerr << "cms::Exception caught\n";
1322     std::cerr << x.what() << '\n';
1323     exitCode = 2;
1324   } catch (std::exception& x) {
1325     std::cerr << "std::exception caught\n";
1326     std::cerr << x.what() << '\n';
1327     exitCode = 3;
1328   } catch (...) {
1329     std::cerr << "Unknown exception caught\n";
1330     exitCode = 4;
1331   }
1332 
1333   dumper.printErrors(std::cerr);
1334   return exitCode;
1335 }