CMS 3D CMS Logo

/data/refman/pasoursint/CMSSW_5_3_4/src/HLTrigger/Timer/src/FastTimerService.cc

Go to the documentation of this file.
00001 // FIXME
00002 // we are by-passing the ME's when filling the plots, so we might need to call the ME's update() by hand
00003 
00004 
00005 // system headers
00006 #ifdef __linux
00007 #include <time.h>
00008 #else
00009 typedef int clockid_t;
00010 #define CLOCK_REALTIME               0
00011 #define CLOCK_MONOTONIC              1
00012 #define CLOCK_PROCESS_CPUTIME_ID     2
00013 #define CLOCK_THREAD_CPUTIME_ID      3
00014 #endif
00015 
00016 // C++ headers
00017 #include <cmath>
00018 #include <iostream>
00019 #include <iomanip>
00020 #include <string>
00021 #include <sstream>
00022 #include <tr1/unordered_set>
00023 #include <tr1/unordered_map>
00024 
00025 // boost headers
00026 // for forward compatibility with boost 1.47
00027 #define BOOST_FILESYSTEM_VERSION 3
00028 #include <boost/filesystem/path.hpp>
00029 #include <boost/format.hpp>
00030 
00031 // CMSSW headers
00032 #include "FWCore/ServiceRegistry/interface/ActivityRegistry.h"
00033 #include "FWCore/ServiceRegistry/interface/Service.h"
00034 #include "FWCore/ParameterSet/interface/ParameterSet.h"
00035 #include "FWCore/Framework/interface/TriggerNamesService.h"
00036 #include "FWCore/MessageLogger/interface/MessageLogger.h"
00037 #include "DataFormats/Common/interface/HLTPathStatus.h"
00038 #include "DataFormats/Provenance/interface/EventID.h"
00039 #include "DataFormats/Provenance/interface/Timestamp.h"
00040 #include "DataFormats/Provenance/interface/ModuleDescription.h"
00041 #include "DQMServices/Core/interface/DQMStore.h"
00042 #include "DQMServices/Core/interface/MonitorElement.h"
00043 #include "HLTrigger/Timer/interface/FastTimerService.h"
00044 #include "HLTrigger/Timer/interface/CPUAffinity.h"
00045 
00046 
00047 // file-static methods to fill a vector of strings with "(dup.) (...)" entries
00048 static
00049 void fill_dups(std::vector<std::string> & dups, unsigned int size) {
00050   dups.reserve(size);
00051   for (unsigned int i = dups.size(); i < size; ++i)
00052     dups.push_back( (boost::format("(dup.) (%d)") % i).str() );
00053 }
00054 
00055 
00056 FastTimerService::FastTimerService(const edm::ParameterSet & config, edm::ActivityRegistry & registry) :
00057   // configuration
00058   m_timer_id(                   config.getUntrackedParameter<bool>(        "useRealTimeClock",          true ) ? CLOCK_REALTIME : CLOCK_THREAD_CPUTIME_ID),
00059   m_is_cpu_bound(               false ),
00060   m_enable_timing_paths(        config.getUntrackedParameter<bool>(        "enableTimingPaths",         true ) ),
00061   m_enable_timing_modules(      config.getUntrackedParameter<bool>(        "enableTimingModules",       true ) ),
00062   m_enable_timing_exclusive(    config.getUntrackedParameter<bool>(        "enableTimingExclusive",     false) ),
00063   m_enable_timing_summary(      config.getUntrackedParameter<bool>(        "enableTimingSummary",       false) ),
00064   m_skip_first_path(            config.getUntrackedParameter<bool>(        "skipFirstPath",             false) ),
00065   // dqm configuration
00066   m_enable_dqm(                  config.getUntrackedParameter<bool>(       "enableDQM",                 true ) ),
00067   m_enable_dqm_bypath_active(    config.getUntrackedParameter<bool>(       "enableDQMbyPathActive",     false) ),
00068   m_enable_dqm_bypath_total(     config.getUntrackedParameter<bool>(       "enableDQMbyPathTotal",      true ) ),
00069   m_enable_dqm_bypath_overhead(  config.getUntrackedParameter<bool>(       "enableDQMbyPathOverhead",   false) ),
00070   m_enable_dqm_bypath_details(   config.getUntrackedParameter<bool>(       "enableDQMbyPathDetails",    false) ),
00071   m_enable_dqm_bypath_counters(  config.getUntrackedParameter<bool>(       "enableDQMbyPathCounters",   true ) ),
00072   m_enable_dqm_bypath_exclusive( config.getUntrackedParameter<bool>(       "enableDQMbyPathExclusive",  false) ),
00073   m_enable_dqm_bymodule(         config.getUntrackedParameter<bool>(       "enableDQMbyModule",         false) ),
00074   m_enable_dqm_bylumi(           config.getUntrackedParameter<bool>(       "enableDQMbyLumi",           false) ),
00075   m_dqm_eventtime_range(         config.getUntrackedParameter<double>(     "dqmTimeRange",              1000.) ),    // ms
00076   m_dqm_eventtime_resolution(    config.getUntrackedParameter<double>(     "dqmTimeResolution",            5.) ),    // ms
00077   m_dqm_pathtime_range(          config.getUntrackedParameter<double>(     "dqmPathTimeRange",           100.) ),    // ms
00078   m_dqm_pathtime_resolution(     config.getUntrackedParameter<double>(     "dqmPathTimeResolution",       0.5) ),    // ms
00079   m_dqm_moduletime_range(        config.getUntrackedParameter<double>(     "dqmModuleTimeRange",          40.) ),    // ms
00080   m_dqm_moduletime_resolution(   config.getUntrackedParameter<double>(     "dqmModuleTimeResolution",     0.2) ),    // ms
00081   m_dqm_path(                    config.getUntrackedParameter<std::string>("dqmPath",      "HLT/TimerService") ),
00082   // caching
00083   m_first_path(0),          // these are initialized at prePathBeginRun(),
00084   m_last_path(0),           // to make sure we cache the correct pointers
00085   m_first_endpath(0),
00086   m_last_endpath(0),
00087   m_is_first_module(false),
00088   // per-event accounting
00089   m_event(0.),
00090   m_source(0.),
00091   m_all_paths(0.),
00092   m_all_endpaths(0.),
00093   // per-job summary
00094   m_summary_events(0),
00095   m_summary_event(0.),
00096   m_summary_source(0.),
00097   m_summary_all_paths(0.),
00098   m_summary_all_endpaths(0.),
00099   // DQM
00100   m_dqms(0),                // these are initialized at postBeginJob(),
00101   m_dqm_event(0),           // to make sure the DQM service has been loaded
00102   m_dqm_source(0),
00103   m_dqm_all_paths(0),
00104   m_dqm_all_endpaths(0),
00105   m_dqm_paths_active_time(0),
00106   m_dqm_paths_total_time(0),
00107   m_dqm_paths_exclusive_time(0),
00108   // per-path and per-module accounting
00109   m_current_path(0),
00110   m_paths(),
00111   m_modules(),
00112   m_cache_paths(),
00113   m_cache_modules()
00114 {
00115   // enable timers if required by DQM plots
00116   m_enable_timing_paths     = m_enable_timing_paths     or m_enable_dqm_bypath_active or m_enable_dqm_bypath_total or m_enable_dqm_bypath_overhead or m_enable_dqm_bypath_details or m_enable_dqm_bypath_counters or m_enable_dqm_bypath_exclusive;
00117   m_enable_timing_modules   = m_enable_timing_modules   or m_enable_dqm_bymodule      or m_enable_dqm_bypath_total or m_enable_dqm_bypath_overhead or m_enable_dqm_bypath_details or m_enable_dqm_bypath_counters or m_enable_dqm_bypath_exclusive;
00118   m_enable_timing_exclusive = m_enable_timing_exclusive or m_enable_dqm_bypath_exclusive;
00119 
00120   registry.watchPreModuleBeginJob( this, & FastTimerService::preModuleBeginJob );
00121   registry.watchPostBeginJob(      this, & FastTimerService::postBeginJob );
00122   registry.watchPostEndJob(        this, & FastTimerService::postEndJob );
00123   registry.watchPrePathBeginRun(   this, & FastTimerService::prePathBeginRun) ;
00124   registry.watchPreProcessEvent(   this, & FastTimerService::preProcessEvent );
00125   registry.watchPostProcessEvent(  this, & FastTimerService::postProcessEvent );
00126   registry.watchPreSource(         this, & FastTimerService::preSource );
00127   registry.watchPostSource(        this, & FastTimerService::postSource );
00128   // watch per-path events
00129   registry.watchPreProcessPath(    this, & FastTimerService::preProcessPath );
00130   registry.watchPostProcessPath(   this, & FastTimerService::postProcessPath );
00131   // watch per-module events if enabled
00132   if (m_enable_timing_modules) {
00133     registry.watchPreModule(         this, & FastTimerService::preModule );
00134     registry.watchPostModule(        this, & FastTimerService::postModule );
00135   }
00136 }
00137 
00138 FastTimerService::~FastTimerService()
00139 {
00140 }
00141 
00142 void FastTimerService::postBeginJob() {
00143   //edm::LogImportant("FastTimerService") << __func__ << "()";
00144 
00145   // check if the process is bound to a single CPU.
00146   // otherwise, the results of the CLOCK_THREAD_CPUTIME_ID timer might be inaccurate
00147   m_is_cpu_bound = CPUAffinity::isCpuBound();
00148   if ((m_timer_id != CLOCK_REALTIME) and not m_is_cpu_bound)
00149     // the process is NOT bound to a single CPU
00150     edm::LogError("FastTimerService") << "this process is NOT bound to a single CPU, the results of the FastTimerService may be undefined";
00151 
00152   edm::service::TriggerNamesService & tns = * edm::Service<edm::service::TriggerNamesService>();
00153   uint32_t size_p = tns.getTrigPaths().size();
00154   uint32_t size_e = tns.getEndPaths().size();
00155   uint32_t size = size_p + size_e;
00156   for (uint32_t i = 0; i < size_p; ++i) {
00157     std::string const & label = tns.getTrigPath(i);
00158     m_paths[label].index = i;
00159   }
00160   for (uint32_t i = 0; i < size_e; ++i) {
00161     std::string const & label = tns.getEndPath(i);
00162     m_paths[label].index = size_p + i;
00163   }
00164 
00165   // cache all pathinfo objects
00166   m_cache_paths.reserve(m_paths.size());
00167   for (auto & keyval: m_paths)
00168     m_cache_paths.push_back(& keyval.second);
00169 
00170   // cache all moduleinfo objects
00171   m_cache_modules.reserve(m_modules.size());
00172   for (auto & keyval: m_modules)
00173     m_cache_modules.push_back(& keyval.second);
00174 
00175   // associate to each path all the modules it contains
00176   for (uint32_t i = 0; i < tns.getTrigPaths().size(); ++i)
00177     fillPathMap( tns.getTrigPath(i), tns.getTrigPathModules(i) );
00178   for (uint32_t i = 0; i < tns.getEndPaths().size(); ++i)
00179     fillPathMap( tns.getEndPath(i), tns.getEndPathModules(i) );
00180 
00181   if (m_enable_dqm)
00182     // load the DQM store
00183     m_dqms = edm::Service<DQMStore>().operator->();
00184 
00185   if (m_dqms) {
00186     if (m_enable_dqm_bylumi) {
00187       // by-lumi plots use a different second-level directory:
00188       //    TimerService   --> TimerService/EventInfo
00189       //    HLT/Timer      --> HLT/EventInfo/Timer
00190       // etc.
00191 
00192       // assume the path to be relative, and to have at least an item
00193       boost::filesystem::path dqm_path(m_dqm_path);
00194       boost::filesystem::path::iterator item = dqm_path.begin();
00195       boost::filesystem::path path = * item++;
00196       path /= "EventInfo";
00197       while (item != dqm_path.end())
00198         path /= * item++;
00199       m_dqm_path = path.generic_string();
00200     }
00201 
00202     // book MonitorElement's
00203     int eventbins  = (int) std::ceil(m_dqm_eventtime_range  / m_dqm_eventtime_resolution);
00204     int pathbins   = (int) std::ceil(m_dqm_pathtime_range   / m_dqm_pathtime_resolution);
00205     int modulebins = (int) std::ceil(m_dqm_moduletime_range / m_dqm_moduletime_resolution);
00206 
00207     m_dqms->setCurrentFolder(m_dqm_path);
00208 
00209     // event plots
00210     m_dqm_event         = m_dqms->book1D("event",        "Event",    eventbins, 0., m_dqm_eventtime_range)->getTH1F();
00211     m_dqm_event         ->StatOverflows(true);
00212     m_dqm_source        = m_dqms->book1D("source",       "Source",   pathbins,  0., m_dqm_pathtime_range)->getTH1F();
00213     m_dqm_source        ->StatOverflows(true);
00214     m_dqm_all_paths     = m_dqms->book1D("all_paths",    "Paths",    eventbins, 0., m_dqm_eventtime_range)->getTH1F();
00215     m_dqm_all_paths     ->StatOverflows(true);
00216     m_dqm_all_endpaths  = m_dqms->book1D("all_endpaths", "EndPaths", pathbins,  0., m_dqm_pathtime_range)->getTH1F();
00217     m_dqm_all_endpaths  ->StatOverflows(true);
00218 
00219     // summary plots
00220     m_dqm_paths_active_time     = m_dqms->bookProfile("paths_active_time",    "Additional time spent in each path", size, -0.5, size-0.5, pathbins, 0., m_dqm_pathtime_range, " ")->getTProfile();
00221     m_dqm_paths_active_time     ->StatOverflows(true);
00222     m_dqm_paths_total_time      = m_dqms->bookProfile("paths_total_time",     "Total time spent in each path",      size, -0.5, size-0.5, pathbins, 0., m_dqm_pathtime_range, " ")->getTProfile();
00223     m_dqm_paths_total_time      ->StatOverflows(true);
00224     m_dqm_paths_exclusive_time  = m_dqms->bookProfile("paths_exclusive_time", "Exclusive time spent in each path",  size, -0.5, size-0.5, pathbins, 0., m_dqm_pathtime_range, " ")->getTProfile();
00225     m_dqm_paths_exclusive_time  ->StatOverflows(true);
00226 
00227     for (uint32_t i = 0; i < size_p; ++i) {
00228       std::string const & label = tns.getTrigPath(i);
00229       if (m_enable_dqm_bypath_active)
00230         m_dqm_paths_active_time    ->GetXaxis()->SetBinLabel(i + 1, label.c_str());
00231       if (m_enable_dqm_bypath_total)
00232         m_dqm_paths_total_time     ->GetXaxis()->SetBinLabel(i + 1, label.c_str());
00233       if (m_enable_dqm_bypath_exclusive)
00234         m_dqm_paths_exclusive_time ->GetXaxis()->SetBinLabel(i + 1, label.c_str());
00235     }
00236     for (uint32_t i = 0; i < size_e; ++i) {
00237       std::string const & label = tns.getEndPath(i);
00238       if (m_enable_dqm_bypath_active)
00239         m_dqm_paths_active_time    ->GetXaxis()->SetBinLabel(i + size_p + 1, label.c_str());
00240       if (m_enable_dqm_bypath_total)
00241         m_dqm_paths_total_time     ->GetXaxis()->SetBinLabel(i + size_p + 1, label.c_str());
00242       if (m_enable_dqm_bypath_exclusive)
00243         m_dqm_paths_exclusive_time ->GetXaxis()->SetBinLabel(i + size_p + 1, label.c_str());
00244     }
00245 
00246     if (m_enable_timing_paths) {
00247       m_dqms->setCurrentFolder((m_dqm_path + "/Paths"));
00248       for (auto & keyval: m_paths) {
00249         std::string const & pathname = keyval.first;
00250         PathInfo          & pathinfo = keyval.second;
00251 
00252         if (m_enable_dqm_bypath_active) {
00253           pathinfo.dqm_active       = m_dqms->book1D(pathname + "_active",       pathname + " active time",            pathbins, 0., m_dqm_pathtime_range)->getTH1F();
00254           pathinfo.dqm_active       ->StatOverflows(true);
00255         }
00256 
00257         if (m_enable_dqm_bypath_total) {
00258           pathinfo.dqm_total        = m_dqms->book1D(pathname + "_total",        pathname + " total time",             pathbins, 0., m_dqm_pathtime_range)->getTH1F();
00259           pathinfo.dqm_total        ->StatOverflows(true);
00260         }
00261 
00262         if (m_enable_dqm_bypath_overhead) {
00263           pathinfo.dqm_premodules   = m_dqms->book1D(pathname + "_premodules",   pathname + " pre-modules overhead",   modulebins, 0., m_dqm_moduletime_range)->getTH1F();
00264           pathinfo.dqm_premodules   ->StatOverflows(true);
00265           pathinfo.dqm_intermodules = m_dqms->book1D(pathname + "_intermodules", pathname + " inter-modules overhead", modulebins, 0., m_dqm_moduletime_range)->getTH1F();
00266           pathinfo.dqm_intermodules ->StatOverflows(true);
00267           pathinfo.dqm_postmodules  = m_dqms->book1D(pathname + "_postmodules",  pathname + " post-modules overhead",  modulebins, 0., m_dqm_moduletime_range)->getTH1F();
00268           pathinfo.dqm_postmodules  ->StatOverflows(true);
00269           pathinfo.dqm_overhead     = m_dqms->book1D(pathname + "_overhead",     pathname + " overhead time",          modulebins, 0., m_dqm_moduletime_range)->getTH1F();
00270           pathinfo.dqm_overhead     ->StatOverflows(true);
00271         }
00272 
00273         if (m_enable_dqm_bypath_details or m_enable_dqm_bypath_counters) {
00274           // book histograms for modules-in-paths statistics
00275 
00276           // find histograms X-axis labels
00277           uint32_t id;
00278           std::vector<std::string> const & modules = ((id = tns.findTrigPath(pathname)) != tns.getTrigPaths().size()) ? tns.getTrigPathModules(id) :
00279                                                      ((id = tns.findEndPath(pathname))  != tns.getEndPaths().size())  ? tns.getEndPathModules(id)  :
00280                                                      std::vector<std::string>();
00281 
00282           static std::vector<std::string> dup;
00283           if (modules.size() > dup.size())
00284             fill_dups(dup, modules.size());
00285 
00286           std::vector<const char *> labels(modules.size(), nullptr);
00287           for (uint32_t i = 0; i < modules.size(); ++i)
00288             labels[i] = (pathinfo.modules[i]) ? modules[i].c_str() : dup[i].c_str();
00289           
00290           // book counter histograms
00291           if (m_enable_dqm_bypath_counters) {
00292             pathinfo.dqm_module_counter = m_dqms->book1D(pathname + "_module_counter", pathname + " module counter", modules.size(), -0.5, modules.size() - 0.5)->getTH1F();
00293             // find module labels
00294             for (uint32_t i = 0; i < modules.size(); ++i) {
00295               pathinfo.dqm_module_counter->GetXaxis()->SetBinLabel( i+1, labels[i] );
00296             }
00297           }
00298           // book detailed timing histograms
00299           if (m_enable_dqm_bypath_details) {
00300             pathinfo.dqm_module_active  = m_dqms->book1D(pathname + "_module_active",  pathname + " module active",  modules.size(), -0.5, modules.size() - 0.5)->getTH1F();
00301             pathinfo.dqm_module_total   = m_dqms->book1D(pathname + "_module_total",   pathname + " module total",   modules.size(), -0.5, modules.size() - 0.5)->getTH1F();
00302             // find module labels
00303             for (uint32_t i = 0; i < modules.size(); ++i) {
00304               pathinfo.dqm_module_active ->GetXaxis()->SetBinLabel( i+1, labels[i] );
00305               pathinfo.dqm_module_total  ->GetXaxis()->SetBinLabel( i+1, labels[i] );
00306             }
00307           }
00308         }
00309 
00310         // book exclusive path time histograms
00311         if (m_enable_dqm_bypath_exclusive) {
00312           pathinfo.dqm_exclusive = m_dqms->book1D(pathname + "_exclusive", pathname + " exclusive time", pathbins, 0., m_dqm_pathtime_range)->getTH1F();
00313           pathinfo.dqm_exclusive ->StatOverflows(true);
00314         }
00315 
00316       }
00317     }
00318    
00319     if (m_enable_dqm_bymodule) {
00320       m_dqms->setCurrentFolder((m_dqm_path + "/Modules"));
00321       for (auto & keyval: m_modules) {
00322         std::string const & label  = keyval.first->moduleLabel();
00323         ModuleInfo        & module = keyval.second;
00324         module.dqm_active = m_dqms->book1D(label, label, modulebins, 0., m_dqm_moduletime_range)->getTH1F();
00325         module.dqm_active->StatOverflows(true);
00326       }
00327     }
00328 
00329   }
00330 }
00331 
00332 void FastTimerService::postEndJob() {
00333   //edm::LogImportant("FastTimerService") << __func__ << "()";
00334 
00335   if (m_enable_timing_summary) {
00336     // print a timing sumary for the whle job
00337     edm::service::TriggerNamesService & tns = * edm::Service<edm::service::TriggerNamesService>();
00338 
00339     std::ostringstream out;
00340     out << std::fixed << std::setprecision(6);
00341     out << "FastReport " << (m_timer_id == CLOCK_REALTIME ? "(real time) " : "(CPU time)  ") << '\n';
00342     out << "FastReport              " << std::right << std::setw(10) << m_summary_source       / (double) m_summary_events << "  Source"        << '\n';
00343     out << "FastReport              " << std::right << std::setw(10) << m_summary_event        / (double) m_summary_events << "  Event"         << '\n';
00344     out << "FastReport              " << std::right << std::setw(10) << m_summary_all_paths    / (double) m_summary_events << "  all Paths"     << '\n';
00345     out << "FastReport              " << std::right << std::setw(10) << m_summary_all_endpaths / (double) m_summary_events << "  all EndPaths"  << '\n';
00346     if (m_enable_timing_modules) {
00347       double modules_total = 0.;
00348       for (auto & keyval: m_modules)
00349         modules_total += keyval.second.summary_active;
00350       out << "FastReport              " << std::right << std::setw(10) << modules_total          / (double) m_summary_events << "  all Modules"   << '\n';
00351     }
00352     out << '\n';
00353     if (m_enable_timing_paths and not m_enable_timing_modules) {
00354       out << "FastReport " << (m_timer_id == CLOCK_REALTIME ? "(real time) " : "(CPU time)  ")    << "     Active Path" << '\n';
00355       for (auto const & name: tns.getTrigPaths())
00356         out << "FastReport              "
00357             << std::right << std::setw(10) << m_paths[name].summary_active  / (double) m_summary_events << "  "
00358             << name << '\n';
00359       out << '\n';
00360       out << "FastReport " << (m_timer_id == CLOCK_REALTIME ? "(real time) " : "(CPU time)  ")    << "     Active EndPath" << '\n';
00361       for (auto const & name: tns.getEndPaths())
00362         out << "FastReport              "
00363             << std::right << std::setw(10) << m_paths[name].summary_active  / (double) m_summary_events << "  "
00364             << name << '\n';
00365     } else if (m_enable_timing_paths and m_enable_timing_modules) {
00366       out << "FastReport " << (m_timer_id == CLOCK_REALTIME ? "(real time) " : "(CPU time)  ")    << "     Active      Pre-    Inter- Post-mods  Overhead     Total  Path" << '\n';
00367       for (auto const & name: tns.getTrigPaths()) {
00368         out << "FastReport              "
00369             << std::right << std::setw(10) << m_paths[name].summary_active        / (double) m_summary_events << " "
00370             << std::right << std::setw(10) << m_paths[name].summary_premodules    / (double) m_summary_events << " "
00371             << std::right << std::setw(10) << m_paths[name].summary_intermodules  / (double) m_summary_events << " "
00372             << std::right << std::setw(10) << m_paths[name].summary_postmodules   / (double) m_summary_events << " "
00373             << std::right << std::setw(10) << m_paths[name].summary_overhead      / (double) m_summary_events << " "
00374             << std::right << std::setw(10) << m_paths[name].summary_total         / (double) m_summary_events << "  "
00375             << name << '\n';
00376       }
00377       out << '\n';
00378       out << "FastReport " << (m_timer_id == CLOCK_REALTIME ? "(real time) " : "(CPU time)  ")    << "     Active      Pre-    Inter- Post-mods  Overhead     Total  EndPath" << '\n';
00379       for (auto const & name: tns.getEndPaths()) {
00380         out << "FastReport              "
00381             << std::right << std::setw(10) << m_paths[name].summary_active        / (double) m_summary_events << " "
00382             << std::right << std::setw(10) << m_paths[name].summary_premodules    / (double) m_summary_events << " "
00383             << std::right << std::setw(10) << m_paths[name].summary_intermodules  / (double) m_summary_events << " "
00384             << std::right << std::setw(10) << m_paths[name].summary_postmodules   / (double) m_summary_events << " "
00385             << std::right << std::setw(10) << m_paths[name].summary_overhead      / (double) m_summary_events << " "
00386             << std::right << std::setw(10) << m_paths[name].summary_total         / (double) m_summary_events << "  "
00387             << name << '\n';
00388       }
00389     }
00390     out << '\n';
00391     if (m_enable_timing_modules) {
00392       out << "FastReport " << (m_timer_id == CLOCK_REALTIME ? "(real time) " : "(CPU time)  ")    << "     Active  Module" << '\n';
00393       for (auto & keyval: m_modules) {
00394         std::string const & label  = keyval.first->moduleLabel();
00395         ModuleInfo  const & module = keyval.second;
00396         out << "FastReport              " << std::right << std::setw(10) << module.summary_active  / (double) m_summary_events << "  " << label << '\n';
00397       }
00398       out << "FastReport " << (m_timer_id == CLOCK_REALTIME ? "(real time) " : "(CPU time)  ")    << "     Active  Module" << '\n';
00399     }
00400     out << '\n';
00401     edm::LogVerbatim("FastReport") << out.str();
00402   }
00403 
00404   // needed for the DAQ when reconfiguring between runs
00405   reset();
00406 }
00407 
00408 void FastTimerService::reset() {
00409   // caching
00410   m_first_path = 0;          // these are initialized at prePathBeginRun(),
00411   m_last_path = 0;           // to make sure we cache the correct pointers
00412   m_first_endpath = 0;
00413   m_last_endpath = 0;
00414   m_is_first_module = false;
00415   // per-event accounting
00416   m_event = 0.;
00417   m_source = 0.;
00418   m_all_paths = 0.;
00419   m_all_endpaths = 0.;
00420   // per-job summary
00421   m_summary_events = 0;
00422   m_summary_event = 0.;
00423   m_summary_source = 0.;
00424   m_summary_all_paths = 0.;
00425   m_summary_all_endpaths = 0.;
00426   // DQM
00427   m_dqms = 0;
00428   // the DAQ destroys and re-creates the DQM and DQMStore services at each reconfigure, so we don't need to clean them up
00429   m_dqm_event = 0;
00430   m_dqm_source = 0;
00431   m_dqm_all_paths = 0;
00432   m_dqm_all_endpaths = 0;
00433   // per-path and per-module accounting
00434   m_current_path = 0;
00435   m_paths.clear();          // this should destroy all PathInfo objects and Reset the associated plots
00436   m_modules.clear();        // this should destroy all ModuleInfo objects and Reset the associated plots
00437   m_cache_paths.clear();
00438   m_cache_modules.clear();
00439 }
00440 
00441 void FastTimerService::preModuleBeginJob(edm::ModuleDescription const & module) {
00442   //edm::LogImportant("FastTimerService") << __func__ << "(" << & module << ")";
00443   //edm::LogImportant("FastTimerService") << "module " << module.moduleLabel() << " @ " << & module;
00444 
00445   // allocate a counter for each module
00446   m_modules[& module];
00447 }
00448 
00449 void FastTimerService::preProcessEvent(edm::EventID const & id, edm::Timestamp const & stamp) {
00450   //edm::LogImportant("FastTimerService") << __func__ << "(...)";
00451 
00452   // new event, reset the per-event counter
00453   start(m_timer_event);
00454 
00455   // clear the event counters
00456   m_event        = 0;
00457   m_all_paths    = 0;
00458   m_all_endpaths = 0;
00459   for (PathInfo * path: m_cache_paths) {
00460     path->time_active       = 0.;
00461     path->time_premodules   = 0.;
00462     path->time_intermodules = 0.;
00463     path->time_postmodules  = 0.;
00464     path->time_total        = 0.;
00465   }
00466   for (ModuleInfo * module: m_cache_modules) {
00467     module->time_active     = 0.;
00468     module->has_just_run    = false;
00469     module->is_exclusive    = false;
00470   }
00471 }
00472 
00473 void FastTimerService::postProcessEvent(edm::Event const & event, edm::EventSetup const & setup) {
00474   //edm::LogImportant("FastTimerService") << __func__ << "(...)";
00475 
00476   if (m_enable_timing_exclusive) {
00477     for (auto & keyval: m_paths) {
00478       PathInfo & pathinfo = keyval.second;
00479       float exclusive = pathinfo.time_overhead;
00480 
00481       for (uint32_t i = 0; i <= pathinfo.last_run; ++i) {
00482         ModuleInfo * module = pathinfo.modules[i];
00483         if (module == 0)
00484           // this is a module occurring more than once in the same path, skip it after the first occurrence
00485           continue;
00486         if (module->is_exclusive)
00487           exclusive += module->time_active;
00488       }
00489       m_dqm_paths_exclusive_time->Fill(pathinfo.index, exclusive * 1000.);
00490       if (m_enable_dqm_bypath_exclusive)
00491         pathinfo.dqm_exclusive->Fill(exclusive * 1000.);      // convert to ms
00492     }
00493   }
00494 
00495   // stop the per-event timer, and account event time
00496   stop(m_timer_event);
00497   m_event = delta(m_timer_event);
00498   m_summary_event += m_event;
00499   if (m_dqms)
00500     m_dqm_event->Fill(m_event * 1000.);                     // convert to ms
00501 }
00502 
00503 void FastTimerService::preSource() {
00504   //edm::LogImportant("FastTimerService") << __func__ << "()";
00505 
00506   start(m_timer_source);
00507 
00508   // clear the event counters
00509   m_source = 0;
00510 
00511   // keep track of the total number of events
00512   ++m_summary_events;
00513 }
00514 
00515 void FastTimerService::postSource() {
00516   //edm::LogImportant("FastTimerService") << __func__ << "()";
00517 
00518   stop(m_timer_source);
00519   m_source = delta(m_timer_source);
00520   m_summary_source += m_source;
00521   if (m_dqms)
00522     m_dqm_source->Fill(m_source * 1000.);                       // convert to ms
00523 }
00524 
00525 void FastTimerService::prePathBeginRun(std::string const & path ) {
00526   //edm::LogImportant("FastTimerService") << __func__ << "(" << path << ")";
00527 
00528   // cache the pointers to the names of the first and last path and endpath
00529   edm::service::TriggerNamesService & tns = * edm::Service<edm::service::TriggerNamesService>();
00530   if (not m_skip_first_path and not tns.getTrigPaths().empty()) {
00531     if (path == tns.getTrigPaths().front())
00532       m_first_path = & path;
00533     if (path == tns.getTrigPaths().back())
00534       m_last_path = & path;
00535   }
00536   else if (m_skip_first_path and tns.getTrigPaths().size() > 1) {
00537     if (path == tns.getTrigPaths().at(1))
00538       m_first_path = & path;
00539     if (path == tns.getTrigPaths().back())
00540       m_last_path = & path;
00541   }
00542   if (not tns.getEndPaths().empty()) {
00543     if (path == tns.getEndPaths().front())
00544       m_first_endpath = & path;
00545     if (path == tns.getEndPaths().back())
00546       m_last_endpath = & path;
00547   }
00548 }
00549 
00550 void FastTimerService::preProcessPath(std::string const & path ) {
00551   //edm::LogImportant("FastTimerService") << __func__ << "(" << path << ")";
00552 
00553   // prepare to measure the time spent between the beginning of the path and the execution of the first module
00554   m_is_first_module = true;
00555 
00556   PathMap<PathInfo>::iterator keyval = m_paths.find(path);
00557   if (keyval != m_paths.end()) {
00558     m_current_path = & keyval->second;
00559 
00560     if (m_enable_timing_modules) {
00561       // reset the status of this path's modules
00562       for (ModuleInfo * module: m_current_path->modules)
00563         if (module)
00564           module->has_just_run = false;
00565     }
00566   } else {
00567     // should never get here
00568     m_current_path = 0;
00569     edm::LogError("FastTimerService") << "FastTimerService::preProcessPath: unexpected path " << path;
00570   }
00571 
00572   // time each (end)path
00573   start(m_timer_path);
00574 
00575   if (& path == m_first_path) {
00576     // this is the first path, start the "all paths" counter
00577     m_timer_paths.first = m_timer_path.first;
00578   } else if (& path == m_first_endpath) {
00579     // this is the first endpath, start the "all paths" counter
00580     m_timer_endpaths.first = m_timer_path.first;
00581   }
00582 }
00583 
00584 void FastTimerService::postProcessPath(std::string const & path, edm::HLTPathStatus const & status) {
00585   //edm::LogImportant("FastTimerService") << __func__ << "(" << path << ", ...)";
00586 
00587   // time each (end)path
00588   stop(m_timer_path);
00589 
00590   double active = delta(m_timer_path);
00591 
00592   // if enabled, account each (end)path
00593   if (m_enable_timing_paths) {
00594 
00595     PathInfo & pathinfo = * m_current_path;
00596     pathinfo.time_active = active;
00597     pathinfo.summary_active += active;
00598 
00599     if (m_dqms) {
00600       m_dqm_paths_active_time->Fill(pathinfo.index, active * 1000.);     // convert to ms
00601       if (m_enable_dqm_bypath_active)
00602         pathinfo.dqm_active->Fill(active * 1000.);                      // convert to ms
00603     }
00604 
00605     // measure the time spent between the execution of the last module and the end of the path
00606     if (m_enable_timing_modules) {
00607       double pre      = 0.;                 // time spent before the first active module
00608       double inter    = 0.;                 // time spent between active modules
00609       double post     = 0.;                 // time spent after the last active module
00610       double overhead = 0.;                 // time spent before, between, or after modules
00611       double current  = 0.;                 // time spent in modules active in the current path
00612       double total    = active;             // total per-path time, including modules already run as part of other paths
00613 
00614       // implementation note:
00615       // "active"   has already measured all the time spent in this path
00616       // "current"  will be the sum of the time spent inside each module while running this path, so that
00617       // "overhead" will be active - current
00618       // "total"    will be active + the sum of the time spent in non-active modules
00619 
00620       uint32_t last_run = status.index();     // index of the last module run in this path
00621       for (uint32_t i = 0; i <= last_run; ++i) {
00622         ModuleInfo * module = pathinfo.modules[i];
00623 
00624         // fill counter histograms - also for duplicate modules, to properly extract rejection information
00625         if (m_enable_dqm_bypath_counters)
00626           pathinfo.dqm_module_counter->Fill(i);
00627         
00628         if (module == 0)
00629           // this is a module occurring more than once in the same path, skip it after the first occurrence
00630           continue;
00631 
00632         if (module->has_just_run) {
00633           current += module->time_active;
00634           module->is_exclusive = true;
00635         } else {
00636           total   += module->time_active;
00637           module->is_exclusive = false;
00638         }
00639 
00640         // fill detailed timing histograms
00641         if (m_enable_dqm_bypath_details) {
00642           // fill the total time for all non-duplicate modules
00643           pathinfo.dqm_module_total->Fill(i, module->time_active);
00644           if (module->has_just_run)
00645             // fill the active time only for module actually running in this path
00646             pathinfo.dqm_module_active->Fill(i, module->time_active);
00647         }
00648 
00649       }
00650 
00651       if (status.accept())
00652         if (m_enable_dqm_bypath_counters)
00653           pathinfo.dqm_module_counter->Fill(pathinfo.modules.size());
00654 
00655       if (m_is_first_module) {
00656         // no modules were active during this path, account all the time as overhead
00657         pre      = 0.;
00658         inter    = 0.;
00659         post     = active;
00660         overhead = active;
00661       } else {
00662         // extract overhead information
00663         pre      = delta(m_timer_path.first,    m_timer_first_module);
00664         post     = delta(m_timer_module.second, m_timer_path.second);
00665         inter    = active - pre - current - post;
00666         // take care of numeric precision and rounding errors - the timer is less precise than nanosecond resolution
00667         if (std::abs(inter) < 1e-9)
00668           inter = 0.;
00669         overhead = active - current;
00670         // take care of numeric precision and rounding errors - the timer is less precise than nanosecond resolution
00671         if (std::abs(overhead) < 1e-9)
00672           overhead = 0.;
00673       }
00674 
00675       pathinfo.time_premodules       = pre;
00676       pathinfo.time_intermodules     = inter;
00677       pathinfo.time_postmodules      = post;
00678       pathinfo.time_overhead         = overhead;
00679       pathinfo.time_total            = total;
00680       pathinfo.summary_premodules   += pre;
00681       pathinfo.summary_intermodules += inter;
00682       pathinfo.summary_postmodules  += post;
00683       pathinfo.summary_overhead     += overhead;
00684       pathinfo.summary_total        += total;
00685       pathinfo.last_run              = last_run;
00686       if (m_dqms) {
00687         if (m_enable_dqm_bypath_overhead) {
00688           pathinfo.dqm_premodules  ->Fill(pre      * 1000.);      // convert to ms
00689           pathinfo.dqm_intermodules->Fill(inter    * 1000.);      // convert to ms
00690           pathinfo.dqm_postmodules ->Fill(post     * 1000.);      // convert to ms
00691           pathinfo.dqm_overhead    ->Fill(overhead * 1000.);      // convert to ms
00692         }
00693         m_dqm_paths_total_time->Fill(pathinfo.index, total * 1000.);
00694         if (m_enable_dqm_bypath_total) {
00695           pathinfo.dqm_total       ->Fill(total    * 1000.);      // convert to ms
00696         }
00697       }
00698     }
00699   }
00700 
00701   if (& path == m_last_path) {
00702     // this is the last path, stop and account the "all paths" counter
00703     m_timer_paths.second = m_timer_path.second;
00704     m_all_paths = delta(m_timer_paths);
00705     m_summary_all_paths += m_all_paths;
00706     if (m_dqms)
00707       m_dqm_all_paths->Fill(m_all_paths * 1000.);               // convert to ms
00708   } else if (& path == m_last_endpath) {
00709     // this is the last endpath, stop and account the "all endpaths" counter
00710     m_timer_endpaths.second = m_timer_path.second;
00711     m_all_endpaths = delta(m_timer_endpaths);
00712     m_summary_all_endpaths += m_all_endpaths;
00713     if (m_dqms)
00714       m_dqm_all_endpaths->Fill(m_all_endpaths * 1000.);         // convert to ms
00715   }
00716 
00717 }
00718 
00719 void FastTimerService::preModule(edm::ModuleDescription const & module) {
00720   //edm::LogImportant("FastTimerService") << __func__ << "(" << & module << ")";
00721 
00722   // this is ever called only if m_enable_timing_modules = true
00723   assert(m_enable_timing_modules);
00724 
00725   // time each module
00726   start(m_timer_module);
00727 
00728   if (m_is_first_module) {
00729     m_is_first_module = false;
00730 
00731     // measure the time spent between the beginning of the path and the execution of the first module
00732     m_timer_first_module = m_timer_module.first;
00733   } 
00734 }
00735 
00736 void FastTimerService::postModule(edm::ModuleDescription const & module) {
00737   //edm::LogImportant("FastTimerService") << __func__ << "(" << & module << ")";
00738 
00739   // this is ever called only if m_enable_timing_modules = true
00740   assert(m_enable_timing_modules);
00741 
00742   // time and account each module
00743   stop(m_timer_module);
00744 
00745   ModuleMap<ModuleInfo>::iterator keyval = m_modules.find(& module);
00746   if (keyval != m_modules.end()) {
00747     double time = delta(m_timer_module);
00748     ModuleInfo & module = keyval->second;
00749     module.has_just_run    = true;
00750     module.time_active     = time;
00751     module.summary_active += time;
00752 
00753     if (m_dqms and m_enable_dqm_bymodule)
00754       module.dqm_active->Fill(time * 1000.);                    // convert to ms
00755   } else {
00756     // should never get here
00757     edm::LogError("FastTimerService") << "FastTimerService::postModule: unexpected module " << module.moduleLabel();
00758   }
00759 }
00760 
00761 // find the module description associated to a module, by label
00762 edm::ModuleDescription const * FastTimerService::findModuleDescription(const std::string & label) const {
00763   // no descriptions are associated to an empty label
00764   if (label.empty())
00765     return 0;
00766 
00767   // fix the name of negated or ignored modules
00768   std::string const & target = (label[0] == '!' or label[0] == '-') ? label.substr(1) : label;
00769 
00770   for (auto const & keyval: m_modules) {
00771     if (keyval.first == 0) {
00772       // this should never happen, but it would cause a segmentation fault to insert a null pointer in the path map, se we explicitly check for it and skip it
00773       edm::LogError("FastTimerService") << "FastTimerService::findModuleDescription: invalid entry detected in ModuleMap<ModuleInfo> m_modules, skipping";
00774       continue;
00775     }
00776     if (keyval.first->moduleLabel() == target) {
00777       return keyval.first;
00778     }
00779   }
00780   // not found
00781   return 0;
00782 }
00783 
00784 // associate to a path all the modules it contains
00785 void FastTimerService::fillPathMap(std::string const & name, std::vector<std::string> const & modules) {
00786   std::vector<ModuleInfo *> & pathmap = m_paths[name].modules;
00787   pathmap.reserve( modules.size() );
00788   std::tr1::unordered_set<edm::ModuleDescription const *> pool;        // keep track of inserted modules
00789   for (auto const & module: modules) {
00790     edm::ModuleDescription const * md = findModuleDescription(module);
00791     if (md == 0) {
00792       // no matching module was found
00793       pathmap.push_back( 0 );
00794     } else if (pool.insert(md).second) {
00795       // new module
00796       pathmap.push_back( & m_modules[md] );
00797     } else {
00798       // duplicate module
00799       pathmap.push_back( 0 );
00800     }
00801   }
00802 }
00803 
00804 
00805 // query the current module/path/event
00806 // Note: these functions incur in a "per-call timer overhead" (see above), currently of the order of 340ns
00807 
00808 // return the time spent since the last preModule() event
00809 double FastTimerService::currentModuleTime() const {
00810   struct timespec now;
00811   gettime(now);
00812   return delta(m_timer_module.first, now);
00813 }
00814 
00815 // return the time spent since the last preProcessPath() event
00816 double FastTimerService::currentPathTime() const {
00817   struct timespec now;
00818   gettime(now);
00819   return delta(m_timer_path.first, now);
00820 }
00821 
00822 // return the time spent since the last preProcessEvent() event
00823 double FastTimerService::currentEventTime() const {
00824   struct timespec now;
00825   gettime(now);
00826   return delta(m_timer_event.first, now);
00827 }
00828 
00829 // query the time spent in a module (available after the module has run)
00830 double FastTimerService::queryModuleTime(const edm::ModuleDescription & module) const {
00831   ModuleMap<ModuleInfo>::const_iterator keyval = m_modules.find(& module);
00832   if (keyval != m_modules.end()) {
00833     return keyval->second.time_active;
00834   } else {
00835     edm::LogError("FastTimerService") << "FastTimerService::postModule: unexpected module " << module.moduleLabel();
00836     return 0.;
00837   }
00838 }
00839 
00840 // query the time spent in a path (available after the path has run)
00841 double FastTimerService::queryPathActiveTime(const std::string & path) const {
00842   PathMap<PathInfo>::const_iterator keyval = m_paths.find(path);
00843   if (keyval != m_paths.end()) {
00844     return keyval->second.time_active;
00845   } else {
00846     edm::LogError("FastTimerService") << "FastTimerService::postModule: unexpected path " << path;
00847     return 0.;
00848   }
00849 }
00850 
00851 // query the total time spent in a path (available after the path has run)
00852 double FastTimerService::queryPathTotalTime(const std::string & path) const {
00853   PathMap<PathInfo>::const_iterator keyval = m_paths.find(path);
00854   if (keyval != m_paths.end()) {
00855     return keyval->second.time_total;
00856   } else {
00857     edm::LogError("FastTimerService") << "FastTimerService::postModule: unexpected path " << path;
00858     return 0.;
00859   }
00860 }
00861 
00862 // query the time spent in the current event's source (available during event processing)
00863 double FastTimerService::querySourceTime() const {
00864   return m_source;
00865 }
00866 
00867 // query the time spent in the current event's paths (available during endpaths)
00868 double FastTimerService::queryPathsTime() const {
00869   return m_all_paths;
00870 }
00871 
00872 // query the time spent in the current event's endpaths (available after all endpaths have run)
00873 double FastTimerService::queryEndPathsTime() const {
00874   return m_all_endpaths;
00875 }
00876 
00877 // query the time spent processing the current event (available after the event has been processed)
00878 double FastTimerService::queryEventTime() const {
00879   return m_event;
00880 }
00881