CMS 3D CMS Logo

CMSSW_4_4_3_patch1/src/DQMServices/Components/src/DQMFileSaver.cc

Go to the documentation of this file.
00001 #include "DQMServices/Components/src/DQMFileSaver.h"
00002 #include "DQMServices/Core/interface/DQMStore.h"
00003 #include "DQMServices/Core/interface/MonitorElement.h"
00004 #include "FWCore/Framework/interface/Event.h"
00005 #include "FWCore/Framework/interface/Run.h"
00006 #include "FWCore/Framework/interface/LuminosityBlock.h"
00007 #include "FWCore/ParameterSet/interface/ParameterSet.h"
00008 #include "FWCore/Version/interface/GetReleaseVersion.h"
00009 #include "FWCore/ServiceRegistry/interface/Service.h"
00010 #include "FWCore/MessageLogger/interface/MessageLogger.h"
00011 #include "FWCore/MessageLogger/interface/JobReport.h"
00012 #include <sys/stat.h>
00013 #include <unistd.h>
00014 #include <iostream>
00015 #include <vector>
00016 #include <string>
00017 #include <TString.h>
00018 #include <TSystem.h>
00019 
00020 //--------------------------------------------------------
00021 static void
00022 getAnInt(const edm::ParameterSet &ps, int &value, const std::string &name)
00023 {
00024   value = ps.getUntrackedParameter<int>(name, value);
00025   if (value < 1 && value != -1)
00026     throw cms::Exception("DQMFileSaver")
00027       << "Invalid '" << name << "' parameter '" << value
00028       << "'.  Must be -1 or >= 1.";
00029 }
00030 
00031 void
00032 DQMFileSaver::saveForOffline(const std::string &workflow, int run, int lumi)
00033 {
00034 
00035   char suffix[64];
00036   sprintf(suffix, "R%09d", run);
00037 
00038   char rewrite[128];
00039   if (lumi == 0) // save for run
00040     sprintf(rewrite, "\\1Run %d/\\2/Run summary", run);
00041   else
00042     sprintf(rewrite, "\\1Run %d/\\2/By Lumi Section %d-%d", irun_, ilumi_, ilumi_);
00043 
00044   size_t pos = 0;
00045   std::string wflow;
00046   wflow.reserve(workflow.size() + 3);
00047   wflow = workflow;
00048   while ((pos = wflow.find('/', pos)) != std::string::npos)
00049     wflow.replace(pos++, 1, "__");
00050     
00051   std::string filename = fileBaseName_ + suffix + wflow + ".root";
00052 
00053   if (lumi == 0) // save for run
00054   {
00055     // set run end flag
00056     dbe_->cd();
00057     dbe_->setCurrentFolder("Info/ProvInfo");
00058 
00059     // do this, because ProvInfo is not yet run in offline DQM
00060     MonitorElement* me = dbe_->get("Info/ProvInfo/CMSSW"); 
00061     if (!me) me = dbe_->bookString("CMSSW",edm::getReleaseVersion().c_str() );
00062     
00063     me = dbe_->get("Info/ProvInfo/runIsComplete");
00064     if (!me) me = dbe_->bookFloat("runIsComplete");
00065 
00066     if (me)
00067     { 
00068       if (runIsComplete_)
00069         me->Fill(1.);
00070       else
00071         me->Fill(0.);
00072     }
00073 
00074     dbe_->save(filename,
00075              "", 
00076              "^(Reference/)?([^/]+)", 
00077              rewrite,
00078              (DQMStore::SaveReferenceTag) saveReference_,
00079              saveReferenceQMin_,
00080              fileUpdate_);
00081   }
00082   else // save EventInfo folders for luminosity sections
00083   {
00084     std::vector<std::string> systems = (dbe_->cd(), dbe_->getSubdirs());
00085 
00086     std::cout << " DQMFileSaver: storing EventInfo folders for Run: " 
00087               << irun_ << ", Lumi Section: " << ilumi_ << ", Subsystems: " ;
00088               
00089     for (size_t i = 0, e = systems.size(); i != e; ++i) {
00090       if (systems[i] != "Reference") {
00091         dbe_->cd();
00092         std::cout << systems[i] << "  " ;
00093         dbe_->save(filename,
00094            systems[i]+"/EventInfo", "^(Reference/)?([^/]+)", rewrite,
00095            DQMStore::SaveWithoutReference,
00096            dqm::qstatus::STATUS_OK,
00097            fileUpdate_);
00098         // from now on update newly created file
00099         if (fileUpdate_=="RECREATE") fileUpdate_="UPDATE";
00100       }
00101     }
00102     std::cout << "\n";
00103   }
00104 
00105   if (pastSavedFiles_.size() == 0)
00106   {
00107     // save JobReport upon creation of file (once per job)
00108     saveJobReport(filename);
00109     pastSavedFiles_.push_back(filename);
00110   }
00111   
00112 }
00113 
00114 static void
00115 doSaveForOnline(std::list<std::string> &pastSavedFiles,
00116                 size_t numKeepSavedFiles,
00117                 DQMStore *store,
00118                 const std::string &filename,
00119                 const std::string &directory,
00120                 const std::string &rxpat,
00121                 const std::string &rewrite,
00122                 DQMStore::SaveReferenceTag saveref,
00123                 int saveRefQMin)
00124 {
00125   store->save(filename, directory , rxpat, 
00126          rewrite, saveref, saveRefQMin);
00127   pastSavedFiles.push_back(filename);
00128   if (pastSavedFiles.size() > numKeepSavedFiles)
00129   {
00130     remove(pastSavedFiles.front().c_str());
00131     pastSavedFiles.pop_front();
00132   }
00133 }
00134 
00135 void
00136 DQMFileSaver::saveForOnline(const std::string &suffix, const std::string &rewrite)
00137 {
00138   std::vector<std::string> systems = (dbe_->cd(), dbe_->getSubdirs());
00139 
00140   for (size_t i = 0, e = systems.size(); i != e; ++i)
00141   {
00142     if (systems[i] != "Reference")
00143     {
00144       dbe_->cd();
00145       if (MonitorElement* me = dbe_->get(systems[i] + "/EventInfo/processName"))
00146       {
00147         doSaveForOnline(pastSavedFiles_, numKeepSavedFiles_, dbe_,
00148                         fileBaseName_ + me->getStringValue() + suffix + ".root",
00149                         "", "^(Reference/)?([^/]+)", rewrite,
00150                         (DQMStore::SaveReferenceTag) saveReference_,
00151                         saveReferenceQMin_);
00152         return;
00153       }
00154     }
00155   }
00156   
00157   // look for EventInfo folder in an unorthodox location
00158   for (size_t i = 0, e = systems.size(); i != e; ++i)
00159     if (systems[i] != "Reference")
00160     { 
00161       dbe_->cd();
00162       std::vector<MonitorElement*> pNamesVector = dbe_->getMatchingContents("^" + systems[i] + "/.*/EventInfo/processName",lat::Regexp::Perl);
00163       std::cout << "pNames vector size:" << pNamesVector.size() << std::endl ;
00164       if (pNamesVector.size() > 0){
00165         doSaveForOnline(pastSavedFiles_, numKeepSavedFiles_, dbe_,
00166                         fileBaseName_ + systems[i] + suffix + ".root",
00167                         "", "^(Reference/)?([^/]+)", rewrite,
00168                         (DQMStore::SaveReferenceTag) saveReference_,
00169                         saveReferenceQMin_);
00170         pNamesVector.clear();
00171         return;
00172       }
00173     }
00174 
00175   // if no EventInfo Folder is found, then store subsystem wise
00176   for (size_t i = 0, e = systems.size(); i != e; ++i)
00177     if (systems[i] != "Reference")
00178       doSaveForOnline(pastSavedFiles_, numKeepSavedFiles_, dbe_,
00179                       fileBaseName_ + systems[i] + suffix + ".root",
00180                       systems[i], "^(Reference/)?([^/]+)", rewrite,
00181                       (DQMStore::SaveReferenceTag) saveReference_,
00182                       saveReferenceQMin_);
00183 }
00184 
00185 void
00186 DQMFileSaver::saveJobReport(const std::string &filename)
00187 {
00188 
00189   // Report the file to job report service.
00190   edm::Service<edm::JobReport> jr;
00191   if (jr.isAvailable())
00192   {
00193     std::map<std::string, std::string> info;
00194     info["Source"] = "DQMStore";
00195     info["FileClass"] = "DQM";
00196     jr->reportAnalysisFile(filename, info);
00197   }
00198 
00199 }
00200 
00201 //--------------------------------------------------------
00202 DQMFileSaver::DQMFileSaver(const edm::ParameterSet &ps)
00203   : convention_ (Offline),
00204     workflow_ (""),
00205     producer_ ("DQM"),
00206     dirName_ ("."),
00207     version_ (1),
00208     runIsComplete_ (false),
00209     saveByLumiSection_ (-1),
00210     saveByEvent_ (-1),
00211     saveByMinute_ (-1),
00212     saveByTime_ (-1),
00213     saveByRun_ (1),
00214     saveAtJobEnd_ (false),
00215     saveReference_ (DQMStore::SaveWithReference),
00216     saveReferenceQMin_ (dqm::qstatus::STATUS_OK),
00217     forceRunNumber_ (-1),
00218     fileBaseName_ (""),
00219     fileUpdate_ ("RECREATE"),
00220     dbe_ (&*edm::Service<DQMStore>()),
00221     irun_ (-1),
00222     ilumi_ (-1),
00223     ilumiprev_ (-1),
00224     ievent_ (-1),
00225     nrun_ (0),
00226     nlumi_ (0),
00227     nevent_ (0),
00228     numKeepSavedFiles_ (5)
00229 {
00230   // Determine the file saving convention, and adjust defaults accordingly.
00231   std::string convention = ps.getUntrackedParameter<std::string>("convention", "Offline");
00232   if (convention == "Offline")
00233     convention_ = Offline;
00234   else if (convention == "Online")
00235     convention_ = Online;
00236   else
00237     throw cms::Exception("DQMFileSaver")
00238       << "Invalid 'convention' parameter '" << convention << "'."
00239       << "  Expected one of 'Online' or 'Offline'.";
00240 
00241   // If this isn't online convention, check workflow.
00242   if (convention_ != Online)
00243   {
00244     workflow_ = ps.getUntrackedParameter<std::string>("workflow", workflow_);
00245     if (workflow_.empty()
00246         || workflow_[0] != '/'
00247         || *workflow_.rbegin() == '/'
00248         || std::count(workflow_.begin(), workflow_.end(), '/') != 3
00249         || workflow_.find_first_not_of("ABCDEFGHIJKLMNOPQRSTUVWXYZ"
00250                                        "abcdefghijklmnopqrstuvwxyz"
00251                                        "0123456789"
00252                                        "-_/") != std::string::npos)
00253       throw cms::Exception("DQMFileSaver")
00254         << "Invalid 'workflow' parameter '" << workflow_
00255         << "'.  Expected '/A/B/C'.";
00256   }
00257   else if (! ps.getUntrackedParameter<std::string>("workflow", "").empty())
00258     throw cms::Exception("DQMFileSaver")
00259       << "The 'workflow' parameter must be empty in 'Online' convention.";
00260   else // for online set parameters
00261   {
00262     workflow_="/Global/Online/P5";
00263   }
00264     
00265   // Allow file producer to be set to specific values in certain conditions.
00266   producer_ = ps.getUntrackedParameter<std::string>("producer", producer_);
00267   if (convention_ == Online
00268       && producer_ != "DQM"
00269       && producer_ != "HLTDQM"
00270       && producer_ != "Playback")
00271   {
00272     throw cms::Exception("DQMFileSaver")
00273       << "Invalid 'producer' parameter '" << producer_
00274       << "'.  Expected 'DQM', 'HLTDQM' or 'Playback'.";
00275   }
00276   else if (convention_ != Online && producer_ != "DQM")
00277   {
00278     throw cms::Exception("DQMFileSaver")
00279       << "Invalid 'producer' parameter '" << producer_
00280       << "'.  Expected 'DQM'.";
00281   }
00282 
00283   // version number to be used in filename
00284   version_ = ps.getUntrackedParameter<int>("version", version_);
00285   // flag to signal that file contains data from complete run
00286   runIsComplete_ = ps.getUntrackedParameter<bool>("runIsComplete", runIsComplete_);
00287 
00288   // Check how we should save the references.
00289   std::string refsave = ps.getUntrackedParameter<std::string>("referenceHandling", "default");
00290   if (refsave == "default")
00291     ;
00292   else if (refsave == "skip") 
00293   {
00294     saveReference_ = DQMStore::SaveWithoutReference;
00295   //  std::cout << "skip saving all references" << std::endl;
00296   }
00297   else if (refsave == "all")
00298   {
00299     saveReference_ = DQMStore::SaveWithReference;
00300   //  std::cout << "saving all references" << std::endl;
00301   }
00302   else if (refsave == "qtests")
00303   {
00304     saveReference_ = DQMStore::SaveWithReferenceForQTest;
00305   //  std::cout << "saving qtest references" << std::endl;
00306   }
00307   else
00308     throw cms::Exception("DQMFileSaver")
00309       << "Invalid 'referenceHandling' parameter '" << refsave
00310       << "'.  Expected 'default', 'skip', 'all' or 'qtests'.";
00311 
00312   // Check minimum required quality test result for which reference is saved.
00313   saveReferenceQMin_ = ps.getUntrackedParameter<int>("referenceRequireStatus", saveReferenceQMin_);
00314 
00315   // Get and check the output directory.
00316   struct stat s;
00317   dirName_ = ps.getUntrackedParameter<std::string>("dirName", dirName_);
00318   if (dirName_.empty() || stat(dirName_.c_str(), &s) == -1)
00319     throw cms::Exception("DQMFileSaver")
00320       << "Invalid 'dirName' parameter '" << dirName_ << "'.";
00321 
00322   // Find out when and how to save files.  The following contraints apply:
00323   // - For online, allow files to be saved at event and time intervals.
00324   // - For online and offline, allow files to be saved per run, lumi and job end
00325   // - For offline allow run number to be overridden (for mc data).
00326   if (convention_ == Online)
00327   {
00328     getAnInt(ps, saveByEvent_, "saveByEvent");
00329     getAnInt(ps, saveByMinute_, "saveByMinute");
00330     getAnInt(ps, saveByTime_, "saveByTime");
00331     getAnInt(ps, numKeepSavedFiles_, "maxSavedFilesCount");
00332   }
00333 
00334   if (convention_ == Online || convention_ == Offline)
00335   {
00336     getAnInt(ps, saveByRun_, "saveByRun");
00337     getAnInt(ps, saveByLumiSection_, "saveByLumiSection");
00338   }
00339 
00340   if (convention_ != Online)
00341   {
00342     getAnInt(ps, forceRunNumber_, "forceRunNumber");
00343     saveAtJobEnd_ = ps.getUntrackedParameter<bool>("saveAtJobEnd", saveAtJobEnd_);
00344   }
00345 
00346   if (saveAtJobEnd_ && forceRunNumber_ < 1)
00347     throw cms::Exception("DQMFileSaver")
00348       << "If saving at the end of the job, the run number must be"
00349       << " overridden to a specific value using 'forceRunNumber'.";
00350 
00351   
00352   // Set up base file name and determine the start time.
00353   char version[8];
00354   sprintf(version, "_V%04d_", int(version_));
00355   version[7]='\0';
00356   fileBaseName_ = dirName_ + "/" + producer_ + version;
00357   gettimeofday(&start_, 0);
00358   saved_ = start_;
00359 
00360   // Log some information what we will do.
00361   edm::LogInfo("DQMFileSaver")
00362     << "DQM file saving settings:\n"
00363     << " using base file name '" << fileBaseName_ << "'\n"
00364     << " forcing run number " << forceRunNumber_ << "\n"
00365     << " saving every " << saveByLumiSection_ << " lumi section(s)\n"
00366     << " saving every " << saveByEvent_ << " event(s)\n"
00367     << " saving every " << saveByMinute_ << " minute(s)\n"
00368     << " saving every 2^n*" << saveByTime_ << " minutes \n"
00369     << " saving every " << saveByRun_ << " run(s)\n"
00370     << " saving at job end: " << (saveAtJobEnd_ ? "yes" : "no") << "\n"
00371     << " keeping at most " << numKeepSavedFiles_ << " files\n";
00372 }
00373 
00374 //--------------------------------------------------------
00375 void
00376 DQMFileSaver::beginJob()
00377 {
00378   irun_ = ilumi_ = ilumiprev_ = ievent_ = -1;
00379   nrun_ = nlumi_ = nevent_ = 0;
00380 }
00381 
00382 void
00383 DQMFileSaver::beginRun(const edm::Run &r, const edm::EventSetup &)
00384 {
00385   irun_     = (forceRunNumber_ == -1 ? r.id().run() : forceRunNumber_);
00386   ++nrun_;
00387 }
00388 
00389 void
00390 DQMFileSaver::beginLuminosityBlock(const edm::LuminosityBlock &l, const edm::EventSetup &)
00391 {
00392   ilumi_    = l.id().luminosityBlock();
00393   if (ilumiprev_ == -1) ilumiprev_ = ilumi_;
00394   ++nlumi_;
00395 }
00396 
00397 void DQMFileSaver::analyze(const edm::Event &e, const edm::EventSetup &)
00398 {
00399   ++nevent_;
00400 
00401   ievent_   = e.id().event();
00402 
00403   // Check if we should save for this event.
00404   char suffix[64];
00405   if (ievent_ > 0 && saveByEvent_ > 0 && nevent_ == saveByEvent_)
00406   {
00407     if (convention_ != Online)
00408       throw cms::Exception("DQMFileSaver")
00409         << "Internal error, can save files by event"
00410         << " only in Online mode.";
00411 
00412     sprintf(suffix, "_R%09d_E%08d", irun_, ievent_);
00413     saveForOnline(suffix, "\\1\\2");
00414     nevent_ = 0;
00415   }
00416 
00417   // Check if we should save due to elapsed time.
00418   if ( ievent_ > 0 && ( saveByMinute_ > 0 || saveByTime_ > 0 ) )
00419   {
00420     if (convention_ != Online)
00421       throw cms::Exception("DQMFileSaver")
00422         << "Internal error, can save files by time"
00423         << " only in Online mode.";
00424 
00425     // Compute elapsed time in minutes.
00426     struct timeval tv;
00427     gettimeofday(&tv, 0);
00428 
00429     double totalelapsed = ((tv.tv_sec + tv.tv_usec*1e-6)
00430                  - (start_.tv_sec + start_.tv_usec*1e-6)) / 60;
00431     double elapsed = ((tv.tv_sec + tv.tv_usec*1e-6)
00432                       - (saved_.tv_sec + saved_.tv_usec*1e-6)) / 60;
00433 
00434     // Save if enough time has elapsed since the last save.
00435     if ( (saveByMinute_ > 0 && elapsed > saveByMinute_ ) ||
00436          (saveByTime_ > 0   && totalelapsed > saveByTime_ ) )
00437     {
00438       if ( saveByTime_ > 0 ) saveByTime_ *= 2;
00439       saved_ = tv;
00440       sprintf(suffix, "_R%09d_T%08d", irun_, int(totalelapsed));
00441       char rewrite[64]; sprintf(rewrite, "\\1Run %d/\\2/Run summary", irun_);
00442       saveForOnline(suffix, rewrite);
00443     }
00444   }
00445 }
00446 
00447 void
00448 DQMFileSaver::endLuminosityBlock(const edm::LuminosityBlock &, const edm::EventSetup &)
00449 {
00450 
00451   if (ilumi_ > 0 && saveByLumiSection_ > 0 )
00452   {
00453     if (convention_ != Online && convention_ != Offline )
00454       throw cms::Exception("DQMFileSaver")
00455         << "Internal error, can save files at end of lumi block"
00456         << " only in Online or Offline mode.";
00457 
00458     if (convention_ == Online && nlumi_ == saveByLumiSection_) // insist on lumi section ordering
00459     {
00460       char suffix[64];
00461       char rewrite[128];
00462       sprintf(suffix, "_R%09d_L%06d", irun_, ilumi_);
00463       sprintf(rewrite, "\\1Run %d/\\2/By Lumi Section %d-%d", irun_, ilumiprev_, ilumi_);
00464       saveForOnline(suffix, rewrite);
00465       ilumiprev_ = -1;
00466       nlumi_ = 0;
00467     }
00468     if (convention_ == Offline)
00469       saveForOffline(workflow_, irun_, ilumi_);
00470   }
00471 }
00472 
00473 void
00474 DQMFileSaver::endRun(const edm::Run &, const edm::EventSetup &)
00475 {
00476   if (irun_ > 0 && saveByRun_ > 0 && nrun_ == saveByRun_)
00477   {
00478     if (convention_ == Online)
00479     {
00480       char suffix[64]; sprintf(suffix, "_R%09d", irun_);
00481       char rewrite[64]; sprintf(rewrite, "\\1Run %d/\\2/Run summary", irun_);
00482       saveForOnline(suffix, rewrite);
00483     }
00484     else if (convention_ == Offline)
00485       saveForOffline(workflow_, irun_, 0);
00486     else
00487       throw cms::Exception("DQMFileSaver")
00488         << "Internal error.  Can only save files in endRun()"
00489         << " in Online and Offline modes.";
00490 
00491     nrun_ = 0;
00492   }
00493 }
00494 
00495 void
00496 DQMFileSaver::endJob(void)
00497 { 
00498   if (saveAtJobEnd_)
00499   {
00500     if (convention_ == Offline && forceRunNumber_ > 0)
00501       saveForOffline(workflow_, forceRunNumber_, 0);
00502     else
00503       throw cms::Exception("DQMFileSaver")
00504         << "Internal error.  Can only save files at the end of the"
00505         << " job in Offline mode with run number overridden.";
00506   }
00507     
00508 }