Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2025-03-14 23:36:19

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