Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2022-10-20 23:30:49

0001 
0002 // -*- C++ -*-
0003 //
0004 //
0005 // 10/23/07 mf        In an attempt to get clues about (or ene) the
0006 //                does-not-output-branches behavior, changed the
0007 //                generic os<< lines in JobReport::JobReportImpl::writeOutputFile
0008 //                to direct use of LogInfo.
0009 //
0010 // 4/8/08   mf        Encase the logdesc for in <CDATA> ... </CDATA>
0011 //
0012 // 6/19/08  mf        reportMessageInfo()
0013 //
0014 // 24 June 2008   ewv  Correct format for CDATA and for second instance of reportError
0015 
0016 //
0017 // Original Author:  Marc Paterno
0018 //
0019 
0020 #include "FWCore/MessageLogger/interface/JobReport.h"
0021 #include "FWCore/Utilities/interface/Map.h"
0022 #include "FWCore/Utilities/interface/EDMException.h"
0023 
0024 // The part of tinyxml used in JobReport was reviewed and
0025 // determined to be threadsafe.
0026 #include "tinyxml2.h"
0027 #include <fstream>
0028 #include <iomanip>
0029 #include <ostream>
0030 #include <sstream>
0031 
0032 namespace edm {
0033   /*
0034    * Note that output formatting is spattered across these classes
0035    * If something outside these classes requires access to the
0036    * same formatting then we need to refactor it into a common library
0037    */
0038 
0039   template <typename S, typename T>
0040   S& formatFile(T const& f, S& os) {
0041     tinyxml2::XMLDocument doc;
0042     if (f.fileHasBeenClosed) {
0043       os << "\n<State  Value=\"closed\"/>";
0044     } else {
0045       os << "\n<State  Value=\"open\"/>";
0046     }
0047     os << "\n<LFN>" << doc.NewText(f.logicalFileName.c_str())->Value() << "</LFN>";
0048     os << "\n<PFN>" << doc.NewText(f.physicalFileName.c_str())->Value() << "</PFN>";
0049     os << "\n<Catalog>" << doc.NewText(f.catalog.c_str())->Value() << "</Catalog>";
0050     os << "\n<ModuleLabel>" << doc.NewText(f.moduleLabel.c_str())->Value() << "</ModuleLabel>";
0051     os << "\n<GUID>" << f.guid << "</GUID>";
0052     os << "\n<Branches>";
0053     for (auto const& branch : f.branchNames) {
0054       os << "\n  <Branch>" << doc.NewText(branch.c_str())->Value() << "</Branch>";
0055       doc.DeleteChildren();
0056     }
0057     os << "\n</Branches>";
0058     return os;
0059   }
0060   /*
0061    * Note that output formatting is spattered across these classes
0062    * If something outside these classes requires access to the
0063    * same formatting then we need to refactor it into a common library
0064    */
0065   template <typename S>
0066   S& print(S& os, JobReport::InputFile const& f) {
0067     tinyxml2::XMLDocument doc;
0068     os << "\n<InputFile>";
0069     formatFile(f, os);
0070     os << "\n<InputType>" << f.inputType << "</InputType>";
0071     os << "\n<InputSourceClass>" << doc.NewText(f.inputSourceClassName.c_str())->Value() << "</InputSourceClass>";
0072     os << "\n<EventsRead>" << f.numEventsRead << "</EventsRead>";
0073     return os;
0074   }
0075 
0076   template <typename S>
0077   S& print(S& os, JobReport::OutputFile const& f) {
0078     tinyxml2::XMLDocument doc;
0079     formatFile(f, os);
0080     os << "\n<OutputModuleClass>" << doc.NewText(f.outputModuleClassName.c_str())->Value() << "</OutputModuleClass>";
0081     os << "\n<TotalEvents>" << f.numEventsWritten << "</TotalEvents>\n";
0082     os << "\n<DataType>" << doc.NewText(f.dataType.c_str())->Value() << "</DataType>\n";
0083     os << "\n<BranchHash>" << doc.NewText(f.branchHash.c_str())->Value() << "</BranchHash>\n";
0084     return os;
0085   }
0086 
0087   template <typename S>
0088   S& print(S& os, JobReport::RunReport const& rep) {
0089     os << "\n<Run ID=\"" << rep.runNumber << "\">\n";
0090 
0091     for (auto const& il : rep.lumiSectionsToNEvents) {
0092       if (std::numeric_limits<unsigned long>::max() == il.second) {
0093         os << "   <LumiSection ID=\"" << il.first << "\"/>\n";
0094 
0095       } else {
0096         os << "   <LumiSection ID=\"" << il.first << "\" NEvents=\"" << il.second << "\"/>\n";
0097       }
0098     }
0099     os << "</Run>\n";
0100     return os;
0101   }
0102 
0103   std::ostream& operator<<(std::ostream& os, JobReport::InputFile const& f) { return print(os, f); }
0104   std::ostream& operator<<(std::ostream& os, JobReport::OutputFile const& f) { return print(os, f); }
0105   std::ostream& operator<<(std::ostream& os, JobReport::RunReport const& f) { return print(os, f); }
0106 
0107   JobReport::InputFile& JobReport::JobReportImpl::getInputFileForToken(InputType inputType, JobReport::Token t) {
0108     InputFile* inputFile = nullptr;
0109     if (inputType == InputType::SecondarySource) {
0110       if (t >= inputFilesSecSource_.size()) {
0111         throw edm::Exception(edm::errors::LogicError) << "Access reported for secondary source input file with token "
0112                                                       << t << " but no matching input file is found\n";
0113       }
0114       inputFile = &inputFilesSecSource_[t];
0115     } else {
0116       if (t >= inputFiles_.size()) {
0117         throw edm::Exception(edm::errors::LogicError)
0118             << "Access reported for input file with token " << t << " but no matching input file is found\n";
0119       }
0120       inputFile = &inputFiles_[t];
0121     }
0122     if (inputFile->fileHasBeenClosed) {
0123       throw edm::Exception(edm::errors::LogicError)
0124           << "Access reported for input file with token " << t << " after this file has been closed.\n"
0125           << "File record follows:\n"
0126           << *inputFile << '\n';
0127     }
0128     return *inputFile;
0129   }
0130 
0131   JobReport::OutputFile& JobReport::JobReportImpl::getOutputFileForToken(JobReport::Token t) {
0132     if (t >= outputFiles_.size()) {
0133       throw edm::Exception(edm::errors::LogicError)
0134           << "Access reported for output file with token " << t << " but no matching output file is found\n";
0135     }
0136     if (outputFiles_[t].fileHasBeenClosed) {
0137       throw edm::Exception(edm::errors::LogicError)
0138           << "Access reported for output file with token " << t << " after this file has been closed.\n"
0139           << "File record follows:\n"
0140           << outputFiles_[t] << '\n';
0141     }
0142     return outputFiles_[t];
0143   }
0144 
0145   /*
0146    * Add the input file token provided to every output
0147    * file currently available.
0148    * Used whenever a new input file is opened, it's token
0149    * is added to all open output files as a contributor
0150    */
0151   void JobReport::JobReportImpl::insertInputForOutputs(InputType inputType, JobReport::Token t) {
0152     for (auto& outputFile : outputFiles_) {
0153       if (!outputFile.fileHasBeenClosed) {
0154         if (inputType == InputType::SecondarySource) {
0155           outputFile.contributingInputsSecSource.push_back(t);
0156         } else {
0157           outputFile.contributingInputs.push_back(t);
0158         }
0159       }
0160     }
0161   }
0162 
0163   /*
0164    * Write anJobReport::InputFile object to the Logger
0165    * Generate XML string forJobReport::InputFile instance and dispatch to
0166    * job report via MessageLogger
0167    */
0168   void JobReport::JobReportImpl::writeInputFile(JobReport::InputFile const& f) {
0169     if (ost_) {
0170       *ost_ << f;
0171       *ost_ << "\n<Runs>";
0172       for (auto const& runReport : f.runReports) {
0173         *ost_ << runReport.second;
0174       }
0175       *ost_ << "\n</Runs>\n";
0176       *ost_ << "</InputFile>\n";
0177       *ost_ << std::flush;
0178     }
0179   }
0180 
0181   /*
0182    * Write an OutputFile object to the Logger
0183    * Generate an XML string for the OutputFile provided and
0184    * dispatch it to the logger
0185    * Contributing input tokens are resolved to the input LFN and PFN
0186    *
0187    * TODO: We have not yet addressed the issue where we cleanup not
0188    * contributing input files.
0189    * Also, it is possible to get fake input to output file mappings
0190    * if an input file is open already when a new output file is opened
0191    * but the input gets closed without contributing events to the
0192    * output file due to filtering etc.
0193    *
0194    */
0195   void JobReport::JobReportImpl::writeOutputFile(JobReport::OutputFile const& f) {
0196     tinyxml2::XMLDocument doc;
0197     if (ost_) {
0198       *ost_ << "\n<File>";
0199       *ost_ << f;
0200 
0201       *ost_ << "\n<Runs>";
0202       for (auto const& runReport : f.runReports) {
0203         *ost_ << runReport.second;
0204       }
0205       *ost_ << "\n</Runs>\n";
0206 
0207       *ost_ << "\n<Inputs>";
0208       for (auto token : f.contributingInputs) {
0209         JobReport::InputFile inpFile = inputFiles_.at(token);
0210         *ost_ << "\n<Input>";
0211         *ost_ << "\n  <LFN>" << doc.NewText(inpFile.logicalFileName.c_str())->Value() << "</LFN>";
0212         *ost_ << "\n  <PFN>" << doc.NewText(inpFile.physicalFileName.c_str())->Value() << "</PFN>";
0213         *ost_ << "\n  <FastCopying>" << findOrDefault(f.fastCopyingInputs, inpFile.physicalFileName)
0214               << "</FastCopying>";
0215         *ost_ << "\n</Input>";
0216         doc.DeleteChildren();
0217       }
0218       for (auto token : f.contributingInputsSecSource) {
0219         JobReport::InputFile inpFile = inputFilesSecSource_.at(token);
0220         *ost_ << "\n<Input>";
0221         *ost_ << "\n  <LFN>" << doc.NewText(inpFile.logicalFileName.c_str())->Value() << "</LFN>";
0222         *ost_ << "\n  <PFN>" << doc.NewText(inpFile.physicalFileName.c_str())->Value() << "</PFN>";
0223         *ost_ << "\n  <FastCopying>" << findOrDefault(f.fastCopyingInputs, inpFile.physicalFileName)
0224               << "</FastCopying>";
0225         *ost_ << "\n</Input>";
0226         doc.DeleteChildren();
0227       }
0228       *ost_ << "\n</Inputs>";
0229       *ost_ << "\n</File>\n";
0230     }
0231   }
0232 
0233   /*
0234    *  Flush all open files to logger in event of a problem.
0235    *  Called from JobReport dtor to flush any remaining open files
0236    */
0237   void JobReport::JobReportImpl::flushFiles(void) {
0238     for (auto const& inputFile : inputFiles_) {
0239       if (!(inputFile.fileHasBeenClosed)) {
0240         writeInputFile(inputFile);
0241       }
0242     }
0243     for (auto const& inputFile : inputFilesSecSource_) {
0244       if (!(inputFile.fileHasBeenClosed)) {
0245         writeInputFile(inputFile);
0246       }
0247     }
0248     for (auto const& outputFile : outputFiles_) {
0249       if (!(outputFile.fileHasBeenClosed)) {
0250         writeOutputFile(outputFile);
0251       }
0252     }
0253   }
0254 
0255   void JobReport::JobReportImpl::associateRun(JobReport::Token token, unsigned int runNumber) {
0256     auto& theMap = outputFiles_.at(token).runReports;
0257     std::map<RunNumber, RunReport>::iterator iter(theMap.lower_bound(runNumber));
0258     if (iter == theMap.end() || runNumber < iter->first) {                        // not found
0259       theMap.emplace_hint(iter, runNumber, JobReport::RunReport{runNumber, {}});  // insert it
0260     }
0261   }
0262 
0263   void JobReport::JobReportImpl::associateInputRun(unsigned int runNumber) {
0264     for (auto& inputFile : inputFiles_) {
0265       if (!inputFile.fileHasBeenClosed) {
0266         std::map<RunNumber, RunReport>& theMap = inputFile.runReports;
0267         std::map<RunNumber, RunReport>::iterator iter(theMap.lower_bound(runNumber));
0268         if (iter == theMap.end() || runNumber < iter->first) {                        // not found
0269           theMap.emplace_hint(iter, runNumber, JobReport::RunReport{runNumber, {}});  // insert it
0270         }
0271       }
0272     }
0273   }
0274 
0275   void JobReport::JobReportImpl::associateLumiSection(JobReport::Token token,
0276                                                       unsigned int runNumber,
0277                                                       unsigned int lumiSect,
0278                                                       unsigned long nEvents) {
0279     auto& theMap = outputFiles_.at(token).runReports;
0280     std::map<RunNumber, RunReport>::iterator iter(theMap.lower_bound(runNumber));
0281     if (iter == theMap.end() || runNumber < iter->first) {                                             // not found
0282       theMap.emplace_hint(iter, runNumber, JobReport::RunReport{runNumber, {{{lumiSect, nEvents}}}});  // insert it
0283     } else {
0284       iter->second.lumiSectionsToNEvents[lumiSect] += nEvents;
0285     }
0286   }
0287 
0288   void JobReport::JobReportImpl::associateInputLumiSection(unsigned int runNumber, unsigned int lumiSect) {
0289     for (auto& inputFile : inputFiles_) {
0290       if (!inputFile.fileHasBeenClosed) {
0291         std::map<RunNumber, RunReport>& theMap = inputFile.runReports;
0292         std::map<RunNumber, RunReport>::iterator iter(theMap.lower_bound(runNumber));
0293         if (iter == theMap.end() || runNumber < iter->first) {  // not found
0294           theMap.emplace_hint(
0295               iter,
0296               runNumber,
0297               JobReport::RunReport{runNumber, {{lumiSect, std::numeric_limits<unsigned long>::max()}}});  // insert it
0298         } else {
0299           iter->second.lumiSectionsToNEvents[lumiSect] = std::numeric_limits<unsigned long>::max();
0300         }
0301       }
0302     }
0303   }
0304 
0305   JobReport::~JobReport() {
0306     impl_->flushFiles();
0307     if (impl_->ost_) {
0308       *(impl_->ost_) << "</FrameworkJobReport>\n" << std::flush;
0309     }
0310   }
0311 
0312   void JobReport::temporarilyCloseXML() {
0313     if (impl_->ost_) {
0314       //remember where we were
0315       auto pos = impl_->ost_->tellp();
0316       *(impl_->ost_) << "</FrameworkJobReport>\n" << std::flush;
0317       //overwrite above during next write.
0318       impl_->ost_->seekp(pos);
0319     }
0320   }
0321 
0322   JobReport::JobReport() : impl_(new JobReportImpl(nullptr)) {}
0323 
0324   JobReport::JobReport(std::ostream* iOstream) : impl_(new JobReportImpl(iOstream)) {
0325     if (impl_->ost_) {
0326       *(impl_->ost_) << "<FrameworkJobReport>\n";
0327     }
0328     temporarilyCloseXML();
0329   }
0330 
0331   JobReport::Token JobReport::inputFileOpened(std::string const& physicalFileName,
0332                                               std::string const& logicalFileName,
0333                                               std::string const& catalog,
0334                                               std::string const& inputType,
0335                                               std::string const& inputSourceClassName,
0336                                               std::string const& moduleLabel,
0337                                               std::string const& guid,
0338                                               std::vector<std::string> const& branchNames) {
0339     InputType theInputType = InputType::Primary;
0340     InputFile* newFile = nullptr;
0341     JobReport::Token newToken = 0;
0342 
0343     if (inputType == "mixingFiles") {
0344       theInputType = InputType::SecondarySource;
0345       auto itr = impl_->inputFilesSecSource_.push_back(InputFile());
0346       newFile = &(*itr);
0347       newToken = itr - impl_->inputFilesSecSource_.begin();
0348     } else {
0349       if (inputType == "secondaryFiles") {
0350         theInputType = InputType::SecondaryFile;
0351       }
0352       impl_->inputFiles_.emplace_back();
0353       newFile = &impl_->inputFiles_.back();
0354       newToken = impl_->inputFiles_.size() - 1;
0355     }
0356 
0357     if (theInputType == InputType::Primary) {
0358       impl_->lastOpenedPrimaryInputFile_ = impl_->inputFiles_.size() - 1;
0359     }
0360     newFile->logicalFileName = logicalFileName;
0361     newFile->physicalFileName = physicalFileName;
0362     newFile->catalog = catalog;
0363     newFile->inputType = inputType;
0364     newFile->inputSourceClassName = inputSourceClassName;
0365     newFile->moduleLabel = moduleLabel;
0366     newFile->guid = guid;
0367     newFile->numEventsRead = 0;
0368     newFile->branchNames = branchNames;
0369     newFile->fileHasBeenClosed = false;
0370 
0371     // Add the new input file token to all output files
0372     //  currently open.
0373     impl_->insertInputForOutputs(theInputType, newToken);
0374     return newToken;
0375   }
0376 
0377   void JobReport::eventReadFromFile(InputType inputType, JobReport::Token fileToken) {
0378     JobReport::InputFile& f = impl_->getInputFileForToken(inputType, fileToken);
0379     ++f.numEventsRead;
0380   }
0381 
0382   void JobReport::reportDataType(Token fileToken, std::string const& dataType) {
0383     JobReport::OutputFile& f = impl_->getOutputFileForToken(fileToken);
0384     f.dataType = dataType;
0385   }
0386 
0387   void JobReport::inputFileClosed(InputType inputType, JobReport::Token fileToken) {
0388     JobReport::InputFile& f = impl_->getInputFileForToken(inputType, fileToken);
0389     f.fileHasBeenClosed = true;
0390     std::lock_guard<std::mutex> lock(write_mutex);
0391     if (inputType == InputType::Primary) {
0392       impl_->writeInputFile(f);
0393     } else {
0394       impl_->writeInputFile(f);
0395     }
0396     temporarilyCloseXML();
0397   }
0398 
0399   JobReport::Token JobReport::outputFileOpened(std::string const& physicalFileName,
0400                                                std::string const& logicalFileName,
0401                                                std::string const& catalog,
0402                                                std::string const& outputModuleClassName,
0403                                                std::string const& moduleLabel,
0404                                                std::string const& guid,
0405                                                std::string const& dataType,
0406                                                std::string const& branchHash,
0407                                                std::vector<std::string> const& branchNames) {
0408     auto itr = impl_->outputFiles_.emplace_back();
0409     JobReport::OutputFile& r = *itr;
0410 
0411     r.logicalFileName = logicalFileName;
0412     r.physicalFileName = physicalFileName;
0413     r.catalog = catalog;
0414     r.outputModuleClassName = outputModuleClassName;
0415     r.moduleLabel = moduleLabel;
0416     r.guid = guid;
0417     r.dataType = dataType;
0418     r.branchHash = branchHash;
0419     r.numEventsWritten = 0;
0420     r.branchNames = branchNames;
0421     r.fileHasBeenClosed = false;
0422     //
0423     // Init list of contributors to list of open input file Tokens
0424     //
0425     for (std::vector<Token>::size_type i = 0, iEnd = impl_->inputFiles_.size(); i < iEnd; ++i) {
0426       if (!impl_->inputFiles_[i].fileHasBeenClosed) {
0427         r.contributingInputs.push_back(i);
0428       }
0429     }
0430     for (oneapi::tbb::concurrent_vector<Token>::size_type i = 0, iEnd = impl_->inputFilesSecSource_.size(); i < iEnd;
0431          ++i) {
0432       if (!impl_->inputFilesSecSource_[i].fileHasBeenClosed) {
0433         r.contributingInputsSecSource.push_back(i);
0434       }
0435     }
0436     return itr - impl_->outputFiles_.begin();
0437   }
0438 
0439   void JobReport::eventWrittenToFile(JobReport::Token fileToken, RunNumber_t /*run*/, EventNumber_t) {
0440     JobReport::OutputFile& f = impl_->getOutputFileForToken(fileToken);
0441     ++f.numEventsWritten;
0442   }
0443 
0444   void JobReport::outputFileClosed(JobReport::Token fileToken) {
0445     JobReport::OutputFile& f = impl_->getOutputFileForToken(fileToken);
0446     f.fileHasBeenClosed = true;
0447     std::lock_guard<std::mutex> lock(write_mutex);
0448     impl_->writeOutputFile(f);
0449     temporarilyCloseXML();
0450   }
0451 
0452   void JobReport::reportSkippedEvent(RunNumber_t run, EventNumber_t event) {
0453     if (impl_->ost_) {
0454       std::ostream& msg = *(impl_->ost_);
0455       {
0456         std::lock_guard<std::mutex> lock(write_mutex);
0457         msg << "<SkippedEvent Run=\"" << run << "\"";
0458         msg << " Event=\"" << event << "\" />\n";
0459         temporarilyCloseXML();
0460       }
0461     }
0462   }
0463 
0464   void JobReport::reportFastCopyingStatus(JobReport::Token fileToken,
0465                                           std::string const& inputFileName,
0466                                           bool fastCopying) {
0467     JobReport::OutputFile& f = impl_->getOutputFileForToken(fileToken);
0468     f.fastCopyingInputs.insert(std::make_pair(inputFileName, fastCopying));
0469   }
0470 
0471   void JobReport::reportLumiSection(JobReport::Token token,
0472                                     unsigned int run,
0473                                     unsigned int lumiSectId,
0474                                     unsigned long nEvents) {
0475     impl_->associateLumiSection(token, run, lumiSectId, nEvents);
0476   }
0477 
0478   void JobReport::reportInputLumiSection(unsigned int run, unsigned int lumiSectId) {
0479     impl_->associateInputLumiSection(run, lumiSectId);
0480   }
0481 
0482   void JobReport::reportRunNumber(JobReport::Token token, unsigned int run) { impl_->associateRun(token, run); }
0483 
0484   void JobReport::reportInputRunNumber(unsigned int run) { impl_->associateInputRun(run); }
0485 
0486   void JobReport::reportAnalysisFile(std::string const& fileName, std::map<std::string, std::string> const& fileData) {
0487     tinyxml2::XMLDocument doc;
0488     if (impl_->ost_) {
0489       std::ostream& msg = *(impl_->ost_);
0490       {
0491         std::lock_guard<std::mutex> lock(write_mutex);
0492         msg << "<AnalysisFile>\n"
0493             << "  <FileName>" << doc.NewText(fileName.c_str())->Value() << "</FileName>\n";
0494 
0495         typedef std::map<std::string, std::string>::const_iterator const_iterator;
0496         for (const_iterator pos = fileData.begin(), posEnd = fileData.end(); pos != posEnd; ++pos) {
0497           msg << "  <" << pos->first << "  Value=\"" << pos->second << "\" />"
0498               << "\n";
0499         }
0500         msg << "</AnalysisFile>\n";
0501         temporarilyCloseXML();
0502       }
0503     }
0504   }
0505 
0506   void JobReport::reportError(std::string const& shortDesc, std::string const& longDesc, int const& exitCode) {
0507     if (impl_->ost_) {
0508       {
0509         std::lock_guard<std::mutex> lock(write_mutex);
0510         std::ostream& msg = *(impl_->ost_);
0511         msg << "<FrameworkError ExitStatus=\"" << exitCode << "\" Type=\"" << shortDesc << "\" >\n";
0512         msg << "<![CDATA[\n" << longDesc << "\n]]>\n";
0513         msg << "</FrameworkError>\n";
0514         temporarilyCloseXML();
0515       }
0516     }
0517   }
0518 
0519   void JobReport::reportSkippedFile(std::string const& pfn, std::string const& lfn) {
0520     if (impl_->ost_) {
0521       std::ostream& msg = *(impl_->ost_);
0522       tinyxml2::XMLDocument doc;
0523       tinyxml2::XMLPrinter printer;
0524       tinyxml2::XMLElement* skipped = doc.NewElement("SkippedFile");
0525       skipped->SetAttribute("Pfn", pfn.c_str());
0526       skipped->SetAttribute("Lfn", lfn.c_str());
0527       {
0528         std::lock_guard<std::mutex> lock(write_mutex);
0529         skipped->Accept(&printer);
0530         msg << printer.CStr();
0531         temporarilyCloseXML();
0532       }
0533     }
0534   }
0535 
0536   void JobReport::reportFallbackAttempt(std::string const& pfn, std::string const& lfn, std::string const& err) {
0537     if (impl_->ost_) {
0538       std::ostream& msg = *(impl_->ost_);
0539       tinyxml2::XMLDocument doc;
0540       tinyxml2::XMLPrinter printer;
0541       tinyxml2::XMLElement* fallback = doc.NewElement("FallbackAttempt");
0542       fallback->SetAttribute("Pfn", pfn.c_str());
0543       fallback->SetAttribute("Lfn", lfn.c_str());
0544       {
0545         std::lock_guard<std::mutex> lock(write_mutex);
0546         fallback->Accept(&printer);
0547         msg << printer.CStr();
0548         msg << "<![CDATA[\n" << err << "\n]]>\n";
0549         temporarilyCloseXML();
0550       }
0551     }
0552   }
0553 
0554   void JobReport::reportMemoryInfo(std::vector<std::string> const& memoryData) {
0555     if (impl_->ost_) {
0556       std::lock_guard<std::mutex> lock(write_mutex);
0557       std::ostream& msg = *(impl_->ost_);
0558       msg << "<MemoryService>\n";
0559 
0560       typedef std::vector<std::string>::const_iterator const_iterator;
0561       for (const_iterator pos = memoryData.begin(), posEnd = memoryData.end(); pos != posEnd; ++pos) {
0562         msg << *pos << "\n";
0563       }
0564       msg << "</MemoryService>\n";
0565       temporarilyCloseXML();
0566     }
0567   }
0568 
0569   void JobReport::reportMessageInfo(std::map<std::string, double> const& messageData) {
0570     if (impl_->ost_) {
0571       std::lock_guard<std::mutex> lock(write_mutex);
0572       std::ostream& msg = *(impl_->ost_);
0573       msg << "<MessageSummary>\n";
0574       typedef std::map<std::string, double>::const_iterator const_iterator;
0575       for (const_iterator pos = messageData.begin(), posEnd = messageData.end(); pos != posEnd; ++pos) {
0576         msg << "  <" << pos->first << "  Value=\"" << pos->second << "\" />"
0577             << "\n";
0578       }
0579       msg << "</MessageSummary>\n";
0580       temporarilyCloseXML();
0581     }
0582   }
0583 
0584   void JobReport::reportReadBranches() {
0585     bool expected = false;
0586     if (not impl_->printedReadBranches_.compare_exchange_strong(expected, true))
0587       return;
0588     if (impl_->ost_) {
0589       std::lock_guard<std::mutex> lock(write_mutex);
0590       std::ostream& ost = *(impl_->ost_);
0591       ost << "<ReadBranches>\n";
0592       tinyxml2::XMLDocument doc;
0593       tinyxml2::XMLPrinter printer;
0594       for (auto const& iBranch : impl_->readBranches_) {
0595         tinyxml2::XMLElement* branch = doc.NewElement("Branch");
0596         branch->SetAttribute("Name", iBranch.first.c_str());
0597         branch->SetAttribute("ReadCount", int64_t(iBranch.second));
0598         branch->Accept(&printer);
0599         ost << printer.CStr();
0600         printer.ClearBuffer();
0601       }
0602       for (auto const& iBranch : impl_->readBranchesSecFile_) {
0603         tinyxml2::XMLElement* branch = doc.NewElement("Branch");
0604         branch->SetAttribute("Name", iBranch.first.c_str());
0605         branch->SetAttribute("ReadCount", int64_t(iBranch.second));
0606         branch->Accept(&printer);
0607         ost << printer.CStr();
0608         printer.ClearBuffer();
0609       }
0610       ost << "</ReadBranches>\n";
0611       if (!impl_->readBranchesSecSource_.empty()) {
0612         ost << "<SecondarySourceReadBranches>\n";
0613         for (auto const& iBranch : impl_->readBranchesSecSource_) {
0614           tinyxml2::XMLElement* branch = doc.NewElement("Branch");
0615           branch->SetAttribute("Name", iBranch.first.c_str());
0616           branch->SetAttribute("ReadCount", int64_t(iBranch.second.value().load()));
0617           branch->Accept(&printer);
0618           ost << printer.CStr();
0619           printer.ClearBuffer();
0620         }
0621         ost << "</SecondarySourceReadBranches>\n";
0622       }
0623       temporarilyCloseXML();
0624     }
0625   }
0626 
0627   void JobReport::reportReadBranch(InputType inputType, std::string const& branchName) {
0628     if (inputType == InputType::Primary) {
0629       // Fast cloned branches have already been reported.
0630       std::set<std::string> const& clonedBranches =
0631           impl_->inputFiles_.at(impl_->lastOpenedPrimaryInputFile_).fastClonedBranches;
0632       if (clonedBranches.find(branchName) == clonedBranches.end()) {
0633         ++impl_->readBranches_[branchName];
0634       }
0635     } else if (inputType == InputType::SecondaryFile) {
0636       ++impl_->readBranchesSecFile_[branchName];
0637     } else if (inputType == InputType::SecondarySource) {
0638       ++impl_->readBranchesSecSource_[branchName].value();
0639     }
0640   }
0641 
0642   void JobReport::reportFastClonedBranches(std::set<std::string> const& fastClonedBranches, long long nEvents) {
0643     std::set<std::string>& clonedBranches =
0644         impl_->inputFiles_.at(impl_->lastOpenedPrimaryInputFile_).fastClonedBranches;
0645     for (std::set<std::string>::const_iterator it = fastClonedBranches.begin(), itEnd = fastClonedBranches.end();
0646          it != itEnd;
0647          ++it) {
0648       if (clonedBranches.insert(*it).second) {
0649         impl_->readBranches_[*it] += nEvents;
0650       }
0651     }
0652   }
0653 
0654   void JobReport::reportRandomStateFile(std::string const& name) {
0655     tinyxml2::XMLDocument doc;
0656     if (impl_->ost_) {
0657       std::ostream& msg = *(impl_->ost_);
0658       {
0659         std::lock_guard<std::mutex> lock(write_mutex);
0660         msg << "<RandomServiceStateFile>\n"
0661             << doc.NewText(name.c_str())->Value() << "\n"
0662             << "</RandomServiceStateFile>\n";
0663         temporarilyCloseXML();
0664       }
0665     }
0666   }
0667 
0668   void JobReport::reportPerformanceSummary(std::string const& metricClass,
0669                                            std::map<std::string, std::string> const& metrics) {
0670     if (impl_->ost_) {
0671       std::ostream& msg = *(impl_->ost_);
0672       msg << "<PerformanceReport>\n"
0673           << "  <PerformanceSummary Metric=\"" << metricClass << "\">\n";
0674 
0675       typedef std::map<std::string, std::string>::const_iterator const_iterator;
0676       for (const_iterator iter = metrics.begin(), iterEnd = metrics.end(); iter != iterEnd; ++iter) {
0677         msg << "    <Metric Name=\"" << iter->first << "\" "
0678             << "Value=\"" << iter->second << "\"/>\n";
0679       }
0680 
0681       msg << "  </PerformanceSummary>\n"
0682           << "</PerformanceReport>\n";
0683       temporarilyCloseXML();
0684     }
0685   }
0686 
0687   void JobReport::reportPerformanceForModule(std::string const& metricClass,
0688                                              std::string const& moduleName,
0689                                              std::map<std::string, std::string> const& metrics) {
0690     if (impl_->ost_) {
0691       std::ostream& msg = *(impl_->ost_);
0692       msg << "<PerformanceReport>\n"
0693           << "  <PerformanceModule Metric=\"" << metricClass << "\" "
0694           << " Module=\"" << moduleName << "\" >\n";
0695 
0696       typedef std::map<std::string, std::string>::const_iterator const_iterator;
0697       for (const_iterator iter = metrics.begin(), iterEnd = metrics.end(); iter != iterEnd; ++iter) {
0698         msg << "    <Metric Name=\"" << iter->first << "\" "
0699             << "Value=\"" << iter->second << "\"/>\n";
0700       }
0701 
0702       msg << "  </PerformanceModule>\n"
0703           << "</PerformanceReport>\n";
0704       temporarilyCloseXML();
0705     }
0706   }
0707 
0708   std::string JobReport::dumpFiles(void) {
0709     std::ostringstream msg;
0710 
0711     tinyxml2::XMLDocument doc;
0712     for (auto const& f : impl_->outputFiles_) {
0713       msg << "\n<File>";
0714       msg << f;
0715 
0716       msg << "\n<LumiSections>";
0717       msg << "\n<Inputs>";
0718       typedef std::vector<JobReport::Token>::iterator iterator;
0719       for (auto const& iInput : f.contributingInputs) {
0720         auto const& inpFile = impl_->inputFiles_[iInput];
0721         msg << "\n<Input>";
0722         msg << "\n  <LFN>" << doc.NewText(inpFile.logicalFileName.c_str())->Value() << "</LFN>";
0723         msg << "\n  <PFN>" << doc.NewText(inpFile.physicalFileName.c_str())->Value() << "</PFN>";
0724         msg << "\n  <FastCopying>" << findOrDefault(f.fastCopyingInputs, inpFile.physicalFileName) << "</FastCopying>";
0725         msg << "\n</Input>";
0726         doc.DeleteChildren();
0727       }
0728       msg << "\n</Inputs>";
0729       msg << "\n</File>";
0730     }
0731     return msg.str();
0732   }
0733 
0734 }  // namespace edm