Back to home page

Project CMSSW displayed by LXR

 
 

    


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

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   static constexpr std::string_view kJobReportEndElement = "</FrameworkJobReport>\n";
0306   static constexpr int kMinSizeOfComment = 8;
0307 
0308   JobReport::~JobReport() {
0309     impl_->flushFiles();
0310     if (impl_->ost_) {
0311       //are we actually at the end of the file?
0312       auto pos = impl_->ost_->tellp();
0313       impl_->ost_->seekp(0, std::ios_base::end);
0314       auto endpos = impl_->ost_->tellp();
0315       impl_->ost_->seekp(pos);
0316       if ((endpos - pos) > static_cast<long int>(kJobReportEndElement.size())) {
0317         //need to add some padding so use a comment element
0318         // comment is used since white spaces are converted to a special node
0319         // while comments are usually ignored by xml parsers
0320         auto padding = (endpos - pos) - (kJobReportEndElement.size() + kMinSizeOfComment);
0321         *(impl_->ost_) << "<!--";
0322         for (int i = padding; i > 0; --i) {
0323           (*impl_->ost_) << ' ';
0324         }
0325         *(impl_->ost_) << "-->\n";
0326       }
0327       *(impl_->ost_) << kJobReportEndElement << std::flush;
0328     }
0329   }
0330 
0331   void JobReport::temporarilyCloseXML() {
0332     if (impl_->ost_) {
0333       //remember where we were
0334       auto pos = impl_->ost_->tellp();
0335       if (not errorLogged_) {
0336         *(impl_->ost_) << "<FrameworkError ExitStatus=\"8901\" Type=\"UnexpectedJobTermination\"/>\n";
0337       }
0338       *(impl_->ost_) << kJobReportEndElement << std::flush;
0339 
0340       //overwrite above during next write.
0341       impl_->ost_->seekp(pos);
0342     }
0343   }
0344 
0345   JobReport::JobReport() : impl_(new JobReportImpl(nullptr)) {}
0346 
0347   JobReport::JobReport(std::ostream* iOstream) : impl_(new JobReportImpl(iOstream)) {
0348     if (impl_->ost_) {
0349       *(impl_->ost_) << "<FrameworkJobReport>\n";
0350     }
0351     temporarilyCloseXML();
0352   }
0353 
0354   JobReport::Token JobReport::inputFileOpened(std::string const& physicalFileName,
0355                                               std::string const& logicalFileName,
0356                                               std::string const& catalog,
0357                                               std::string const& inputType,
0358                                               std::string const& inputSourceClassName,
0359                                               std::string const& moduleLabel,
0360                                               std::string const& guid,
0361                                               std::vector<std::string> const& branchNames) {
0362     InputType theInputType = InputType::Primary;
0363     InputFile* newFile = nullptr;
0364     JobReport::Token newToken = 0;
0365 
0366     if (inputType == "mixingFiles") {
0367       theInputType = InputType::SecondarySource;
0368       auto itr = impl_->inputFilesSecSource_.push_back(InputFile());
0369       newFile = &(*itr);
0370       newToken = itr - impl_->inputFilesSecSource_.begin();
0371     } else {
0372       if (inputType == "secondaryFiles") {
0373         theInputType = InputType::SecondaryFile;
0374       }
0375       impl_->inputFiles_.emplace_back();
0376       newFile = &impl_->inputFiles_.back();
0377       newToken = impl_->inputFiles_.size() - 1;
0378     }
0379 
0380     if (theInputType == InputType::Primary) {
0381       impl_->lastOpenedPrimaryInputFile_ = impl_->inputFiles_.size() - 1;
0382     }
0383     newFile->logicalFileName = logicalFileName;
0384     newFile->physicalFileName = physicalFileName;
0385     newFile->catalog = catalog;
0386     newFile->inputType = inputType;
0387     newFile->inputSourceClassName = inputSourceClassName;
0388     newFile->moduleLabel = moduleLabel;
0389     newFile->guid = guid;
0390     newFile->numEventsRead = 0;
0391     newFile->branchNames = branchNames;
0392     newFile->fileHasBeenClosed = false;
0393 
0394     // Add the new input file token to all output files
0395     //  currently open.
0396     impl_->insertInputForOutputs(theInputType, newToken);
0397     return newToken;
0398   }
0399 
0400   void JobReport::eventReadFromFile(InputType inputType, JobReport::Token fileToken) {
0401     JobReport::InputFile& f = impl_->getInputFileForToken(inputType, fileToken);
0402     ++f.numEventsRead;
0403   }
0404 
0405   void JobReport::reportDataType(Token fileToken, std::string const& dataType) {
0406     JobReport::OutputFile& f = impl_->getOutputFileForToken(fileToken);
0407     f.dataType = dataType;
0408   }
0409 
0410   void JobReport::inputFileClosed(InputType inputType, JobReport::Token fileToken) {
0411     JobReport::InputFile& f = impl_->getInputFileForToken(inputType, fileToken);
0412     f.fileHasBeenClosed = true;
0413     std::lock_guard<std::mutex> lock(write_mutex);
0414     if (inputType == InputType::Primary) {
0415       impl_->writeInputFile(f);
0416     } else {
0417       impl_->writeInputFile(f);
0418     }
0419     temporarilyCloseXML();
0420   }
0421 
0422   JobReport::Token JobReport::outputFileOpened(std::string const& physicalFileName,
0423                                                std::string const& logicalFileName,
0424                                                std::string const& catalog,
0425                                                std::string const& outputModuleClassName,
0426                                                std::string const& moduleLabel,
0427                                                std::string const& guid,
0428                                                std::string const& dataType,
0429                                                std::string const& branchHash,
0430                                                std::vector<std::string> const& branchNames) {
0431     auto itr = impl_->outputFiles_.emplace_back();
0432     JobReport::OutputFile& r = *itr;
0433 
0434     r.logicalFileName = logicalFileName;
0435     r.physicalFileName = physicalFileName;
0436     r.catalog = catalog;
0437     r.outputModuleClassName = outputModuleClassName;
0438     r.moduleLabel = moduleLabel;
0439     r.guid = guid;
0440     r.dataType = dataType;
0441     r.branchHash = branchHash;
0442     r.numEventsWritten = 0;
0443     r.branchNames = branchNames;
0444     r.fileHasBeenClosed = false;
0445     //
0446     // Init list of contributors to list of open input file Tokens
0447     //
0448     for (std::vector<Token>::size_type i = 0, iEnd = impl_->inputFiles_.size(); i < iEnd; ++i) {
0449       if (!impl_->inputFiles_[i].fileHasBeenClosed) {
0450         r.contributingInputs.push_back(i);
0451       }
0452     }
0453     for (oneapi::tbb::concurrent_vector<Token>::size_type i = 0, iEnd = impl_->inputFilesSecSource_.size(); i < iEnd;
0454          ++i) {
0455       if (!impl_->inputFilesSecSource_[i].fileHasBeenClosed) {
0456         r.contributingInputsSecSource.push_back(i);
0457       }
0458     }
0459     return itr - impl_->outputFiles_.begin();
0460   }
0461 
0462   void JobReport::eventWrittenToFile(JobReport::Token fileToken, RunNumber_t /*run*/, EventNumber_t) {
0463     JobReport::OutputFile& f = impl_->getOutputFileForToken(fileToken);
0464     ++f.numEventsWritten;
0465   }
0466 
0467   void JobReport::outputFileClosed(JobReport::Token fileToken) {
0468     JobReport::OutputFile& f = impl_->getOutputFileForToken(fileToken);
0469     f.fileHasBeenClosed = true;
0470     std::lock_guard<std::mutex> lock(write_mutex);
0471     impl_->writeOutputFile(f);
0472     temporarilyCloseXML();
0473   }
0474 
0475   void JobReport::reportSkippedEvent(RunNumber_t run, EventNumber_t event) {
0476     if (impl_->ost_) {
0477       std::ostream& msg = *(impl_->ost_);
0478       {
0479         std::lock_guard<std::mutex> lock(write_mutex);
0480         msg << "<SkippedEvent Run=\"" << run << "\"";
0481         msg << " Event=\"" << event << "\" />\n";
0482         temporarilyCloseXML();
0483       }
0484     }
0485   }
0486 
0487   void JobReport::reportFastCopyingStatus(JobReport::Token fileToken,
0488                                           std::string const& inputFileName,
0489                                           bool fastCopying) {
0490     JobReport::OutputFile& f = impl_->getOutputFileForToken(fileToken);
0491     f.fastCopyingInputs.insert(std::make_pair(inputFileName, fastCopying));
0492   }
0493 
0494   void JobReport::reportLumiSection(JobReport::Token token,
0495                                     unsigned int run,
0496                                     unsigned int lumiSectId,
0497                                     unsigned long nEvents) {
0498     impl_->associateLumiSection(token, run, lumiSectId, nEvents);
0499   }
0500 
0501   void JobReport::reportInputLumiSection(unsigned int run, unsigned int lumiSectId) {
0502     impl_->associateInputLumiSection(run, lumiSectId);
0503   }
0504 
0505   void JobReport::reportRunNumber(JobReport::Token token, unsigned int run) { impl_->associateRun(token, run); }
0506 
0507   void JobReport::reportInputRunNumber(unsigned int run) { impl_->associateInputRun(run); }
0508 
0509   void JobReport::reportAnalysisFile(std::string const& fileName, std::map<std::string, std::string> const& fileData) {
0510     tinyxml2::XMLDocument doc;
0511     if (impl_->ost_) {
0512       std::ostream& msg = *(impl_->ost_);
0513       {
0514         std::lock_guard<std::mutex> lock(write_mutex);
0515         msg << "<AnalysisFile>\n"
0516             << "  <FileName>" << doc.NewText(fileName.c_str())->Value() << "</FileName>\n";
0517 
0518         typedef std::map<std::string, std::string>::const_iterator const_iterator;
0519         for (const_iterator pos = fileData.begin(), posEnd = fileData.end(); pos != posEnd; ++pos) {
0520           msg << "  <" << pos->first << "  Value=\"" << pos->second << "\" />"
0521               << "\n";
0522         }
0523         msg << "</AnalysisFile>\n";
0524         temporarilyCloseXML();
0525       }
0526     }
0527   }
0528 
0529   void JobReport::reportError(std::string const& shortDesc, std::string const& longDesc, int const& exitCode) {
0530     if (impl_->ost_) {
0531       {
0532         std::lock_guard<std::mutex> lock(write_mutex);
0533         errorLogged_ = true;
0534         std::ostream& msg = *(impl_->ost_);
0535         msg << "<FrameworkError ExitStatus=\"" << exitCode << "\" Type=\"" << shortDesc << "\" >\n";
0536         msg << "<![CDATA[\n" << longDesc << "\n]]>\n";
0537         msg << "</FrameworkError>\n";
0538         temporarilyCloseXML();
0539       }
0540     }
0541   }
0542 
0543   void JobReport::reportShutdownSignal() {
0544     if (impl_->ost_) {
0545       {
0546         std::lock_guard<std::mutex> lock(write_mutex);
0547         std::ostream& msg = *(impl_->ost_);
0548         msg << "<ShutdownSignal/>\n";
0549         temporarilyCloseXML();
0550       }
0551     }
0552   }
0553 
0554   void JobReport::reportSkippedFile(std::string const& pfn, std::string const& lfn) {
0555     if (impl_->ost_) {
0556       std::ostream& msg = *(impl_->ost_);
0557       tinyxml2::XMLDocument doc;
0558       tinyxml2::XMLPrinter printer;
0559       tinyxml2::XMLElement* skipped = doc.NewElement("SkippedFile");
0560       skipped->SetAttribute("Pfn", pfn.c_str());
0561       skipped->SetAttribute("Lfn", lfn.c_str());
0562       {
0563         std::lock_guard<std::mutex> lock(write_mutex);
0564         skipped->Accept(&printer);
0565         msg << printer.CStr();
0566         temporarilyCloseXML();
0567       }
0568     }
0569   }
0570 
0571   void JobReport::reportFallbackAttempt(std::string const& pfn, std::string const& lfn, std::string const& err) {
0572     if (impl_->ost_) {
0573       std::ostream& msg = *(impl_->ost_);
0574       tinyxml2::XMLDocument doc;
0575       tinyxml2::XMLPrinter printer;
0576       tinyxml2::XMLElement* fallback = doc.NewElement("FallbackAttempt");
0577       fallback->SetAttribute("Pfn", pfn.c_str());
0578       fallback->SetAttribute("Lfn", lfn.c_str());
0579       {
0580         std::lock_guard<std::mutex> lock(write_mutex);
0581         fallback->Accept(&printer);
0582         msg << printer.CStr();
0583         msg << "<![CDATA[\n" << err << "\n]]>\n";
0584         temporarilyCloseXML();
0585       }
0586     }
0587   }
0588 
0589   void JobReport::reportMemoryInfo(std::vector<std::string> const& memoryData) {
0590     if (impl_->ost_) {
0591       std::lock_guard<std::mutex> lock(write_mutex);
0592       std::ostream& msg = *(impl_->ost_);
0593       msg << "<MemoryService>\n";
0594 
0595       typedef std::vector<std::string>::const_iterator const_iterator;
0596       for (const_iterator pos = memoryData.begin(), posEnd = memoryData.end(); pos != posEnd; ++pos) {
0597         msg << *pos << "\n";
0598       }
0599       msg << "</MemoryService>\n";
0600       temporarilyCloseXML();
0601     }
0602   }
0603 
0604   void JobReport::reportMessageInfo(std::map<std::string, double> const& messageData) {
0605     if (impl_->ost_) {
0606       std::lock_guard<std::mutex> lock(write_mutex);
0607       std::ostream& msg = *(impl_->ost_);
0608       msg << "<MessageSummary>\n";
0609       typedef std::map<std::string, double>::const_iterator const_iterator;
0610       for (const_iterator pos = messageData.begin(), posEnd = messageData.end(); pos != posEnd; ++pos) {
0611         msg << "  <" << pos->first << "  Value=\"" << pos->second << "\" />"
0612             << "\n";
0613       }
0614       msg << "</MessageSummary>\n";
0615       temporarilyCloseXML();
0616     }
0617   }
0618 
0619   void JobReport::reportReadBranches() {
0620     bool expected = false;
0621     if (not impl_->printedReadBranches_.compare_exchange_strong(expected, true))
0622       return;
0623     if (impl_->ost_) {
0624       std::lock_guard<std::mutex> lock(write_mutex);
0625       std::ostream& ost = *(impl_->ost_);
0626       ost << "<ReadBranches>\n";
0627       tinyxml2::XMLDocument doc;
0628       tinyxml2::XMLPrinter printer;
0629       for (auto const& iBranch : impl_->readBranches_) {
0630         tinyxml2::XMLElement* branch = doc.NewElement("Branch");
0631         branch->SetAttribute("Name", iBranch.first.c_str());
0632         branch->SetAttribute("ReadCount", int64_t(iBranch.second));
0633         branch->Accept(&printer);
0634         ost << printer.CStr();
0635         printer.ClearBuffer();
0636       }
0637       for (auto const& iBranch : impl_->readBranchesSecFile_) {
0638         tinyxml2::XMLElement* branch = doc.NewElement("Branch");
0639         branch->SetAttribute("Name", iBranch.first.c_str());
0640         branch->SetAttribute("ReadCount", int64_t(iBranch.second));
0641         branch->Accept(&printer);
0642         ost << printer.CStr();
0643         printer.ClearBuffer();
0644       }
0645       ost << "</ReadBranches>\n";
0646       if (!impl_->readBranchesSecSource_.empty()) {
0647         ost << "<SecondarySourceReadBranches>\n";
0648         for (auto const& iBranch : impl_->readBranchesSecSource_) {
0649           tinyxml2::XMLElement* branch = doc.NewElement("Branch");
0650           branch->SetAttribute("Name", iBranch.first.c_str());
0651           branch->SetAttribute("ReadCount", int64_t(iBranch.second.value().load()));
0652           branch->Accept(&printer);
0653           ost << printer.CStr();
0654           printer.ClearBuffer();
0655         }
0656         ost << "</SecondarySourceReadBranches>\n";
0657       }
0658       temporarilyCloseXML();
0659     }
0660   }
0661 
0662   void JobReport::reportReadBranch(InputType inputType, std::string const& branchName) {
0663     if (inputType == InputType::Primary) {
0664       // Fast cloned branches have already been reported.
0665       std::set<std::string> const& clonedBranches =
0666           impl_->inputFiles_.at(impl_->lastOpenedPrimaryInputFile_).fastClonedBranches;
0667       if (clonedBranches.find(branchName) == clonedBranches.end()) {
0668         ++impl_->readBranches_[branchName];
0669       }
0670     } else if (inputType == InputType::SecondaryFile) {
0671       ++impl_->readBranchesSecFile_[branchName];
0672     } else if (inputType == InputType::SecondarySource) {
0673       ++impl_->readBranchesSecSource_[branchName].value();
0674     }
0675   }
0676 
0677   void JobReport::reportFastClonedBranches(std::set<std::string> const& fastClonedBranches, long long nEvents) {
0678     std::set<std::string>& clonedBranches =
0679         impl_->inputFiles_.at(impl_->lastOpenedPrimaryInputFile_).fastClonedBranches;
0680     for (std::set<std::string>::const_iterator it = fastClonedBranches.begin(), itEnd = fastClonedBranches.end();
0681          it != itEnd;
0682          ++it) {
0683       if (clonedBranches.insert(*it).second) {
0684         impl_->readBranches_[*it] += nEvents;
0685       }
0686     }
0687   }
0688 
0689   void JobReport::reportRandomStateFile(std::string const& name) {
0690     tinyxml2::XMLDocument doc;
0691     if (impl_->ost_) {
0692       std::ostream& msg = *(impl_->ost_);
0693       {
0694         std::lock_guard<std::mutex> lock(write_mutex);
0695         msg << "<RandomServiceStateFile>\n"
0696             << doc.NewText(name.c_str())->Value() << "\n"
0697             << "</RandomServiceStateFile>\n";
0698         temporarilyCloseXML();
0699       }
0700     }
0701   }
0702 
0703   void JobReport::reportPerformanceSummary(std::string const& metricClass,
0704                                            std::map<std::string, std::string> const& metrics) {
0705     if (impl_->ost_) {
0706       std::ostream& msg = *(impl_->ost_);
0707       msg << "<PerformanceReport>\n"
0708           << "  <PerformanceSummary Metric=\"" << metricClass << "\">\n";
0709 
0710       typedef std::map<std::string, std::string>::const_iterator const_iterator;
0711       for (const_iterator iter = metrics.begin(), iterEnd = metrics.end(); iter != iterEnd; ++iter) {
0712         msg << "    <Metric Name=\"" << iter->first << "\" "
0713             << "Value=\"" << iter->second << "\"/>\n";
0714       }
0715 
0716       msg << "  </PerformanceSummary>\n"
0717           << "</PerformanceReport>\n";
0718       temporarilyCloseXML();
0719     }
0720   }
0721 
0722   void JobReport::reportPerformanceForModule(std::string const& metricClass,
0723                                              std::string const& moduleName,
0724                                              std::map<std::string, std::string> const& metrics) {
0725     if (impl_->ost_) {
0726       std::ostream& msg = *(impl_->ost_);
0727       msg << "<PerformanceReport>\n"
0728           << "  <PerformanceModule Metric=\"" << metricClass << "\" "
0729           << " Module=\"" << moduleName << "\" >\n";
0730 
0731       typedef std::map<std::string, std::string>::const_iterator const_iterator;
0732       for (const_iterator iter = metrics.begin(), iterEnd = metrics.end(); iter != iterEnd; ++iter) {
0733         msg << "    <Metric Name=\"" << iter->first << "\" "
0734             << "Value=\"" << iter->second << "\"/>\n";
0735       }
0736 
0737       msg << "  </PerformanceModule>\n"
0738           << "</PerformanceReport>\n";
0739       temporarilyCloseXML();
0740     }
0741   }
0742 
0743   std::string JobReport::dumpFiles(void) {
0744     std::ostringstream msg;
0745 
0746     tinyxml2::XMLDocument doc;
0747     for (auto const& f : impl_->outputFiles_) {
0748       msg << "\n<File>";
0749       msg << f;
0750 
0751       msg << "\n<LumiSections>";
0752       msg << "\n<Inputs>";
0753       typedef std::vector<JobReport::Token>::iterator iterator;
0754       for (auto const& iInput : f.contributingInputs) {
0755         auto const& inpFile = impl_->inputFiles_[iInput];
0756         msg << "\n<Input>";
0757         msg << "\n  <LFN>" << doc.NewText(inpFile.logicalFileName.c_str())->Value() << "</LFN>";
0758         msg << "\n  <PFN>" << doc.NewText(inpFile.physicalFileName.c_str())->Value() << "</PFN>";
0759         msg << "\n  <FastCopying>" << findOrDefault(f.fastCopyingInputs, inpFile.physicalFileName) << "</FastCopying>";
0760         msg << "\n</Input>";
0761         doc.DeleteChildren();
0762       }
0763       msg << "\n</Inputs>";
0764       msg << "\n</File>";
0765     }
0766     return msg.str();
0767   }
0768 
0769 }  // namespace edm