Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2022-05-18 03:27:12

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