CMS 3D CMS Logo

CMSSW_4_4_3_patch1/src/HLTrigger/Timer/src/FastTimerService.cc

Go to the documentation of this file.
00001 // system headers
00002 #ifdef __linux
00003 #include <time.h>
00004 #else
00005 typedef int clockid_t;
00006 #define CLOCK_REALTIME               0
00007 #define CLOCK_MONOTONIC              1
00008 #define CLOCK_PROCESS_CPUTIME_ID     2
00009 #define CLOCK_THREAD_CPUTIME_ID      3
00010 #endif
00011 
00012 // C++ headers
00013 #include <cmath>
00014 #include <iostream>
00015 #include <iomanip>
00016 #include <string>
00017 #include <sstream>
00018 #include <tr1/unordered_set>
00019 #include <tr1/unordered_map>
00020 
00021 // boost headers
00022 #include <boost/foreach.hpp>
00023 // for forward compatibility with boost 1.47
00024 #define BOOST_FILESYSTEM_VERSION 3
00025 #include <boost/filesystem/path.hpp>
00026 
00027 // CMSSW headers
00028 #include "FWCore/ServiceRegistry/interface/ActivityRegistry.h"
00029 #include "FWCore/ServiceRegistry/interface/Service.h"
00030 #include "FWCore/ParameterSet/interface/ParameterSet.h"
00031 #include "FWCore/Framework/interface/TriggerNamesService.h"
00032 #include "FWCore/MessageLogger/interface/MessageLogger.h"
00033 #include "DataFormats/Common/interface/HLTPathStatus.h"
00034 #include "DataFormats/Provenance/interface/EventID.h"
00035 #include "DataFormats/Provenance/interface/Timestamp.h"
00036 #include "DataFormats/Provenance/interface/ModuleDescription.h"
00037 #include "DQMServices/Core/interface/DQMStore.h"
00038 #include "DQMServices/Core/interface/MonitorElement.h"
00039 #include "HLTrigger/Timer/interface/FastTimerService.h"
00040 #include "HLTrigger/Timer/interface/CPUAffinity.h"
00041 
00042 
00043 FastTimerService::FastTimerService(const edm::ParameterSet & config, edm::ActivityRegistry & registry) :
00044   // configuration
00045   m_timer_id(               config.getUntrackedParameter<bool>(        "useRealTimeClock",     false) ? CLOCK_REALTIME : CLOCK_THREAD_CPUTIME_ID),
00046   m_is_cpu_bound(           false ),
00047   m_enable_timing_modules(  config.getUntrackedParameter<bool>(        "enableTimingModules",  false) ),
00048   m_enable_timing_paths(    config.getUntrackedParameter<bool>(        "enableTimingPaths",    false) ),
00049   m_enable_timing_summary(  config.getUntrackedParameter<bool>(        "enableTimingSummary",  false) ),
00050   m_enable_dqm(             config.getUntrackedParameter<bool>(        "enableDQM",            false) ),
00051   m_enable_dqm_bylumi(      config.getUntrackedParameter<bool>(        "enableDQMbyLumi",      false) ),
00052   // dqm configuration
00053   m_dqm_time_range(         config.getUntrackedParameter<double>(      "dqmTimeRange",         1000.) ),   // ms
00054   m_dqm_time_resolution(    config.getUntrackedParameter<double>(      "dqmTimeResolution",       5.) ),   // ms
00055   m_dqm_path(               config.getUntrackedParameter<std::string>( "dqmPath",     "TimerService") ),
00056   // caching
00057   m_first_path(0),          // these are initialized at prePathBeginRun(),
00058   m_last_path(0),           // to make sure we cache the correct pointers
00059   m_first_endpath(0),
00060   m_last_endpath(0),
00061   m_is_first_module(false),
00062   // per-event accounting
00063   m_event(0.),
00064   m_source(0.),
00065   m_all_paths(0.),
00066   m_all_endpaths(0.),
00067   // per-job summary
00068   m_summary_events(0),
00069   m_summary_event(0.),
00070   m_summary_source(0.),
00071   m_summary_all_paths(0.),
00072   m_summary_all_endpaths(0.),
00073   // DQM
00074   m_dqms(0),                // these are initialized at postBeginJob(),
00075   m_dqm_event(0),           // to make sure the DQM service has been loaded
00076   m_dqm_source(0),
00077   m_dqm_all_paths(0),
00078   m_dqm_all_endpaths(0),
00079   // per-path and per-module accounting
00080   m_current_path(0),
00081   m_paths(),
00082   m_modules(),
00083   m_cache_paths(),
00084   m_cache_modules()
00085 {
00086   registry.watchPostBeginJob(      this, & FastTimerService::postBeginJob );
00087   registry.watchPostEndJob(        this, & FastTimerService::postEndJob );
00088   registry.watchPrePathBeginRun(   this, & FastTimerService::prePathBeginRun) ;
00089   registry.watchPreProcessEvent(   this, & FastTimerService::preProcessEvent );
00090   registry.watchPostProcessEvent(  this, & FastTimerService::postProcessEvent );
00091   registry.watchPreSource(         this, & FastTimerService::preSource );
00092   registry.watchPostSource(        this, & FastTimerService::postSource );
00093   // watch per-path events
00094   registry.watchPreProcessPath(    this, & FastTimerService::preProcessPath );
00095   registry.watchPostProcessPath(   this, & FastTimerService::postProcessPath );
00096   // watch per-module events if enabled
00097   if (m_enable_timing_modules) {
00098     registry.watchPreModuleBeginJob( this, & FastTimerService::preModuleBeginJob );
00099     registry.watchPreModule(         this, & FastTimerService::preModule );
00100     registry.watchPostModule(        this, & FastTimerService::postModule );
00101   }
00102 }
00103 
00104 FastTimerService::~FastTimerService()
00105 {
00106 }
00107 
00108 void FastTimerService::postBeginJob() {
00109   // check if the process is bound to a single CPU.
00110   // otherwise, the results of the CLOCK_THREAD_CPUTIME_ID timer might be inaccurate
00111   m_is_cpu_bound = CPUAffinity::isCpuBound();
00112   if ((m_timer_id != CLOCK_REALTIME) and not m_is_cpu_bound)
00113     // the process is NOT bound to a single CPU
00114     edm::LogError("FastTimerService") << "this process is NOT bound to a single CPU, the results of the FastTimerService may be undefined";
00115 
00116   edm::service::TriggerNamesService & tns = * edm::Service<edm::service::TriggerNamesService>();
00117   BOOST_FOREACH(std::string const & name, tns.getTrigPaths())
00118     m_paths[name];
00119   BOOST_FOREACH(std::string const & name, tns.getEndPaths())
00120     m_paths[name];
00121 
00122   // cache all pathinfo objects
00123   if (m_enable_timing_paths) {
00124     m_cache_paths.reserve(m_paths.size());
00125     BOOST_FOREACH(PathMap<PathInfo>::value_type & keyval, m_paths)
00126       m_cache_paths.push_back(& keyval.second);
00127   }
00128 
00129   // cache all moduleinfo objects
00130   if (m_enable_timing_modules) {
00131     m_cache_modules.reserve(m_modules.size());
00132     BOOST_FOREACH(ModuleMap<ModuleInfo>::value_type & keyval, m_modules)
00133       m_cache_modules.push_back(& keyval.second);
00134   }
00135 
00136   // associate to each path all the modules it contains
00137   if (m_enable_timing_paths and m_enable_timing_modules) {
00138     for (size_t i = 0; i < tns.getTrigPaths().size(); ++i)
00139       fillPathMap( tns.getTrigPath(i), tns.getTrigPathModules(i) );
00140     for (size_t i = 0; i < tns.getEndPaths().size(); ++i)
00141       fillPathMap( tns.getEndPath(i), tns.getEndPathModules(i) );
00142   }
00143 
00144   if (m_enable_dqm)
00145     // load the DQM store
00146     m_dqms = edm::Service<DQMStore>().operator->();
00147 
00148   if (m_dqms) {
00149     if (m_enable_dqm_bylumi) {
00150       // by-lumi plots use a different second-level directory:
00151       //    TimerService   --> TimerService/EventInfo
00152       //    HLT/Timer      --> HLT/EventInfo/Timer
00153       // etc.
00154 
00155       // assume the path to be relative, and to have at least an item
00156       boost::filesystem::path dqm_path(m_dqm_path);
00157       boost::filesystem::path::iterator item = dqm_path.begin();
00158       boost::filesystem::path path = * item++;
00159       path /= "EventInfo";
00160       while (item != dqm_path.end())
00161         path /= * item++;
00162       m_dqm_path = path.generic_string();
00163     }
00164 
00165     // book MonitorElement's
00166     int bins = (int) std::ceil(m_dqm_time_range / m_dqm_time_resolution);
00167     m_dqms->setCurrentFolder(m_dqm_path);
00168     m_dqm_event         = m_dqms->book1D("event",        "Event",    bins, 0., m_dqm_time_range)->getTH1F();
00169     m_dqm_event         ->StatOverflows(true);
00170     m_dqm_source        = m_dqms->book1D("source",       "Source",   bins, 0., m_dqm_time_range)->getTH1F();
00171     m_dqm_source        ->StatOverflows(true);
00172     m_dqm_all_paths     = m_dqms->book1D("all_paths",    "Paths",    bins, 0., m_dqm_time_range)->getTH1F();
00173     m_dqm_all_paths     ->StatOverflows(true);
00174     m_dqm_all_endpaths  = m_dqms->book1D("all_endpaths", "EndPaths", bins, 0., m_dqm_time_range)->getTH1F();
00175     m_dqm_all_endpaths  ->StatOverflows(true);
00176     // these are actually filled in the harvesting step - but that may happen in a separate step, which no longer has all the information about the endpaths
00177     size_t size_p = tns.getTrigPaths().size();
00178     size_t size_e = tns.getEndPaths().size();
00179     size_t size = size_p + size_e;
00180     TH1F * path_active_time = m_dqms->book1D("path_active_time", "Additional time spent in each path", size, -0.5, size-0.5)->getTH1F();
00181     TH1F * path_total_time  = m_dqms->book1D("path_total_time",  "Total time spent in each path",      size, -0.5, size-0.5)->getTH1F();
00182     for (size_t i = 0; i < size_p; ++i) {
00183       std::string const & label = tns.getTrigPath(i);
00184       path_active_time->GetXaxis()->SetBinLabel(i + 1, label.c_str());
00185       path_total_time ->GetXaxis()->SetBinLabel(i + 1, label.c_str());
00186     }
00187     for (size_t i = 0; i < size_e; ++i) {
00188       std::string const & label = tns.getEndPath(i);
00189       path_active_time->GetXaxis()->SetBinLabel(i + size_p + 1, label.c_str());
00190       path_total_time ->GetXaxis()->SetBinLabel(i + size_p + 1, label.c_str());
00191     }
00192 
00193     if (m_enable_timing_paths) {
00194       m_dqms->setCurrentFolder((m_dqm_path + "/Paths"));
00195       BOOST_FOREACH(PathMap<PathInfo>::value_type & keyval, m_paths) {
00196         std::string const & pathname = keyval.first;
00197         PathInfo          & pathinfo = keyval.second;
00198         pathinfo.dqm_active = m_dqms->book1D(pathname + "_active", pathname + " active time", bins, 0., m_dqm_time_range)->getTH1F();
00199         pathinfo.dqm_active->StatOverflows(true);
00200       }
00201     }
00202 
00203     if (m_enable_timing_modules) {
00204       m_dqms->setCurrentFolder((m_dqm_path + "/Modules"));
00205       BOOST_FOREACH(ModuleMap<ModuleInfo>::value_type & keyval, m_modules) {
00206         std::string const & label  = keyval.first->moduleLabel();
00207         ModuleInfo        & module = keyval.second;
00208         module.dqm_active = m_dqms->book1D(label, label, bins, 0., m_dqm_time_range)->getTH1F();
00209         module.dqm_active->StatOverflows(true);
00210       }
00211     }
00212 
00213     if (m_enable_timing_paths and m_enable_timing_modules) {
00214       m_dqms->setCurrentFolder((m_dqm_path + "/Paths"));
00215       BOOST_FOREACH(PathMap<PathInfo>::value_type & keyval, m_paths) {
00216         std::string const & pathname = keyval.first;
00217         PathInfo          & pathinfo = keyval.second;
00218 #ifdef FASTTIMERSERVICE_DETAILED_OVERHEAD_ACCOUNTING
00219         pathinfo.dqm_premodules   = m_dqms->book1D(pathname + "_premodules",   pathname + " pre-modules overhead",   bins, 0., m_dqm_time_range)->getTH1F();
00220         pathinfo.dqm_premodules  ->StatOverflows(true);
00221         pathinfo.dqm_intermodules = m_dqms->book1D(pathname + "_intermodules", pathname + " inter-modules overhead", bins, 0., m_dqm_time_range)->getTH1F();
00222         pathinfo.dqm_intermodules->StatOverflows(true);
00223         pathinfo.dqm_postmodules  = m_dqms->book1D(pathname + "_postmodules",  pathname + " post-modules overhead",  bins, 0., m_dqm_time_range)->getTH1F();
00224         pathinfo.dqm_postmodules ->StatOverflows(true);
00225 #else
00226         pathinfo.dqm_overhead     = m_dqms->book1D(pathname + "_overhead",     pathname + " overhead time",          bins, 0., m_dqm_time_range)->getTH1F();
00227         pathinfo.dqm_overhead    ->StatOverflows(true);
00228 #endif
00229         pathinfo.dqm_total        = m_dqms->book1D(pathname + "_total",        pathname + " total time",             bins, 0., m_dqm_time_range)->getTH1F();
00230         pathinfo.dqm_total       ->StatOverflows(true);
00231         
00232         // book histograms for modules-in-paths statistics
00233         size_t id;
00234         std::vector<std::string> const & modules = ((id = tns.findTrigPath(pathname)) != tns.getTrigPaths().size()) ? tns.getTrigPathModules(id) :
00235                                                    ((id = tns.findEndPath(pathname))  != tns.getEndPaths().size())  ? tns.getEndPathModules(id)  :
00236                                                    std::vector<std::string>();
00237         pathinfo.dqm_module_counter = m_dqms->book1D(pathname + "_module_counter", pathname + " module counter", modules.size(), -0.5, modules.size() - 0.5)->getTH1F();
00238         pathinfo.dqm_module_active  = m_dqms->book1D(pathname + "_module_active",  pathname + " module active",  modules.size(), -0.5, modules.size() - 0.5)->getTH1F();
00239         pathinfo.dqm_module_total   = m_dqms->book1D(pathname + "_module_total",   pathname + " module total",   modules.size(), -0.5, modules.size() - 0.5)->getTH1F();
00240         // find module labels
00241         for (size_t i = 0; i < modules.size(); ++i) {
00242           if (pathinfo.modules[i]) {
00243             pathinfo.dqm_module_counter->GetXaxis()->SetBinLabel( i+1, modules[i].c_str() );
00244             pathinfo.dqm_module_active ->GetXaxis()->SetBinLabel( i+1, modules[i].c_str() );
00245             pathinfo.dqm_module_total  ->GetXaxis()->SetBinLabel( i+1, modules[i].c_str() );
00246           } else {
00247             pathinfo.dqm_module_counter->GetXaxis()->SetBinLabel( i+1, "(dup.)" );
00248             pathinfo.dqm_module_active ->GetXaxis()->SetBinLabel( i+1, "(dup.)" );
00249             pathinfo.dqm_module_total  ->GetXaxis()->SetBinLabel( i+1, "(dup.)" );
00250           }
00251         }
00252       }
00253     }
00254 
00255   }
00256 }
00257 
00258 void FastTimerService::postEndJob() {
00259   if (not m_enable_timing_summary)
00260     return;
00261 
00262   edm::service::TriggerNamesService & tns = * edm::Service<edm::service::TriggerNamesService>();
00263 
00264   std::ostringstream out;
00265   out << std::fixed << std::setprecision(6);
00266   out << "FastReport " << (m_timer_id == CLOCK_REALTIME ? "(real time) " : "(CPU time)  ") << '\n';
00267   out << "FastReport              " << std::right << std::setw(10) << m_summary_source       / (double) m_summary_events << "  Source"        << '\n';
00268   out << "FastReport              " << std::right << std::setw(10) << m_summary_event        / (double) m_summary_events << "  Event"         << '\n';
00269   out << "FastReport              " << std::right << std::setw(10) << m_summary_all_paths    / (double) m_summary_events << "  all Paths"     << '\n';
00270   out << "FastReport              " << std::right << std::setw(10) << m_summary_all_endpaths / (double) m_summary_events << "  all EndPaths"  << '\n';
00271   if (m_enable_timing_modules) {
00272     double modules_total = 0.;
00273     BOOST_FOREACH(ModuleMap<ModuleInfo>::value_type & keyval, m_modules)
00274       modules_total += keyval.second.summary_active;
00275     out << "FastReport              " << std::right << std::setw(10) << modules_total          / (double) m_summary_events << "  all Modules"   << '\n';
00276   }
00277   out << '\n';
00278   if (m_enable_timing_paths and not m_enable_timing_modules) {
00279     out << "FastReport " << (m_timer_id == CLOCK_REALTIME ? "(real time) " : "(CPU time)  ")    << "     Active Path" << '\n';
00280     BOOST_FOREACH(std::string const & name, tns.getTrigPaths())
00281       out << "FastReport              "
00282           << std::right << std::setw(10) << m_paths[name].summary_active  / (double) m_summary_events << "  "
00283           << name << '\n';
00284     out << '\n';
00285     out << "FastReport " << (m_timer_id == CLOCK_REALTIME ? "(real time) " : "(CPU time)  ")    << "     Active EndPath" << '\n';
00286     BOOST_FOREACH(std::string const & name, tns.getEndPaths())
00287       out << "FastReport              "
00288           << std::right << std::setw(10) << m_paths[name].summary_active  / (double) m_summary_events << "  "
00289           << name << '\n';
00290   } else if (m_enable_timing_paths and m_enable_timing_modules) {
00291 #ifdef FASTTIMERSERVICE_DETAILED_OVERHEAD_ACCOUNTING
00292     out << "FastReport " << (m_timer_id == CLOCK_REALTIME ? "(real time) " : "(CPU time)  ")    << "     Active   Pre-mods Inter-mods  Post-mods      Total  Path" << '\n';
00293 #else
00294     out << "FastReport " << (m_timer_id == CLOCK_REALTIME ? "(real time) " : "(CPU time)  ")    << "     Active   Overhead      Total  Path" << '\n';
00295 #endif
00296     BOOST_FOREACH(std::string const & name, tns.getTrigPaths())
00297       out << "FastReport              "
00298           << std::right << std::setw(10) << m_paths[name].summary_active        / (double) m_summary_events << " "
00299 #ifdef FASTTIMERSERVICE_DETAILED_OVERHEAD_ACCOUNTING
00300           << std::right << std::setw(10) << m_paths[name].summary_premodules    / (double) m_summary_events << " "
00301           << std::right << std::setw(10) << m_paths[name].summary_intermodules  / (double) m_summary_events << " "
00302           << std::right << std::setw(10) << m_paths[name].summary_postmodules   / (double) m_summary_events << " "
00303 #else
00304           << std::right << std::setw(10) << m_paths[name].summary_overhead      / (double) m_summary_events << "  "
00305 #endif
00306           << std::right << std::setw(10) << m_paths[name].summary_total         / (double) m_summary_events << "  "
00307           << name << '\n';
00308     out << '\n';
00309 #ifdef FASTTIMERSERVICE_DETAILED_OVERHEAD_ACCOUNTING
00310     out << "FastReport " << (m_timer_id == CLOCK_REALTIME ? "(real time) " : "(CPU time)  ")    << "     Active   Pre-mods Inter-mods  Post-mods      Total  Path" << '\n';
00311 #else
00312     out << "FastReport " << (m_timer_id == CLOCK_REALTIME ? "(real time) " : "(CPU time)  ")    << "     Active   Overhead      Total  Path" << '\n';
00313 #endif
00314     BOOST_FOREACH(std::string const & name, tns.getEndPaths())
00315       out << "FastReport              "
00316           << std::right << std::setw(10) << m_paths[name].summary_active        / (double) m_summary_events << " "
00317 #ifdef FASTTIMERSERVICE_DETAILED_OVERHEAD_ACCOUNTING
00318           << std::right << std::setw(10) << m_paths[name].summary_premodules    / (double) m_summary_events << " "
00319           << std::right << std::setw(10) << m_paths[name].summary_intermodules  / (double) m_summary_events << " "
00320           << std::right << std::setw(10) << m_paths[name].summary_postmodules   / (double) m_summary_events << " "
00321 #else
00322           << std::right << std::setw(10) << m_paths[name].summary_overhead      / (double) m_summary_events << "  "
00323 #endif
00324           << std::right << std::setw(10) << m_paths[name].summary_total         / (double) m_summary_events << "  "
00325           << name << '\n';
00326   }
00327   out << '\n';
00328   if (m_enable_timing_modules) {
00329     out << "FastReport " << (m_timer_id == CLOCK_REALTIME ? "(real time) " : "(CPU time)  ")    << "     Active  Module" << '\n';
00330     BOOST_FOREACH(ModuleMap<ModuleInfo>::value_type & keyval, m_modules) {
00331       std::string const & label  = keyval.first->moduleLabel();
00332       ModuleInfo  const & module = keyval.second;
00333       out << "FastReport              " << std::right << std::setw(10) << module.summary_active  / (double) m_summary_events << "  " << label << '\n';
00334     }
00335     out << "FastReport " << (m_timer_id == CLOCK_REALTIME ? "(real time) " : "(CPU time)  ")    << "     Active  Module" << '\n';
00336   }
00337   out << '\n';
00338   edm::LogVerbatim("FastReport") << out.str();
00339 }
00340 
00341 void FastTimerService::preModuleBeginJob(edm::ModuleDescription const & module) {
00342   // this is ever called only if m_enable_timing_modules = true
00343   assert(m_enable_timing_modules);
00344 
00345   // allocate a counter for each module
00346   m_modules[& module];
00347 }
00348 
00349 void FastTimerService::preProcessEvent(edm::EventID const & id, edm::Timestamp const & stamp) {
00350   // new event, reset the per-event counter
00351   start(m_timer_event);
00352 
00353   // clear the event counters
00354   m_event        = 0;
00355   m_all_paths    = 0;
00356   m_all_endpaths = 0;
00357   BOOST_FOREACH(PathInfo * path, m_cache_paths) {
00358     path->time_active       = 0.;
00359 #ifdef FASTTIMERSERVICE_DETAILED_OVERHEAD_ACCOUNTING
00360     path->time_premodules   = 0.;
00361     path->time_intermodules = 0.;
00362     path->time_postmodules  = 0.;
00363 #endif
00364     path->time_total        = 0.;
00365   }
00366   BOOST_FOREACH(ModuleInfo * module, m_cache_modules) {
00367     module->time_active     = 0.;
00368   }
00369 }
00370 
00371 void FastTimerService::postProcessEvent(edm::Event const & event, edm::EventSetup const & setup) {
00372   // stop the per-event timer, and account event time
00373   stop(m_timer_event);
00374   m_event = delta(m_timer_event);
00375   m_summary_event += m_event;
00376   if (m_dqms)
00377     m_dqm_event->Fill(m_event * 1000.);     // convert to ms
00378 }
00379 
00380 void FastTimerService::preSource() {
00381   start(m_timer_source);
00382 
00383   // clear the event counters
00384   m_source = 0;
00385 
00386   // keep track of the total number of events
00387   ++m_summary_events;
00388 }
00389 
00390 void FastTimerService::postSource() {
00391   stop(m_timer_source);
00392   m_source = delta(m_timer_source);
00393   m_summary_source += m_source;
00394   if (m_dqms)
00395     m_dqm_source->Fill(m_source * 1000.);                       // convert to ms
00396 }
00397 
00398 void FastTimerService::prePathBeginRun(std::string const & path ) {
00399   // cache the pointers to the names of the first and last path and endpath
00400   edm::service::TriggerNamesService & tns = * edm::Service<edm::service::TriggerNamesService>();
00401   if (path == tns.getTrigPaths().front())
00402     m_first_path = & path;
00403   if (path == tns.getTrigPaths().back())
00404     m_last_path = & path;
00405   if (path == tns.getEndPaths().front())
00406     m_first_endpath = & path;
00407   if (path == tns.getEndPaths().back())
00408     m_last_endpath = & path;
00409 }
00410 
00411 void FastTimerService::preProcessPath(std::string const & path ) {
00412   // prepare to measure the time spent between the beginning of the path and the execution of the first module
00413   m_is_first_module = true;
00414 
00415   PathMap<PathInfo>::iterator keyval = m_paths.find(path);
00416   if (keyval != m_paths.end()) {
00417     m_current_path = & keyval->second;
00418 
00419     if (m_enable_timing_modules) {
00420       // reset the status of this path's modules
00421       BOOST_FOREACH(ModuleInfo * module, m_current_path->modules)
00422         if (module)
00423           module->has_just_run = false;
00424     }
00425   } else {
00426     // should never get here
00427     m_current_path = 0;
00428     edm::LogError("FastTimerService") << "FastTimerService::preProcessPath: unexpected path " << path;
00429   }
00430 
00431   // time each (end)path
00432   start(m_timer_path);
00433 
00434   if (& path == m_first_path) {
00435     // this is the first path, start the "all paths" counter
00436     m_timer_paths.first = m_timer_path.first;
00437   } else if (& path == m_first_endpath) {
00438     // this is the first endpath, start the "all paths" counter
00439     m_timer_endpaths.first = m_timer_path.first;
00440   }
00441 }
00442 
00443 void FastTimerService::postProcessPath(std::string const & path, edm::HLTPathStatus const & status) {
00444   // time each (end)path
00445   stop(m_timer_path);
00446   double active = delta(m_timer_path);
00447 
00448   // if enabled, account each (end)path
00449   if (m_enable_timing_paths) {
00450     PathInfo & pathinfo = * m_current_path;
00451     pathinfo.time_active = active;
00452     pathinfo.summary_active += active;
00453     if (m_dqms)
00454       pathinfo.dqm_active->Fill(active * 1000.);        // convert to ms
00455 
00456     // measure the time spent between the execution of the last module and the end of the path
00457     if (m_enable_timing_modules) {
00458 #ifdef FASTTIMERSERVICE_DETAILED_OVERHEAD_ACCOUNTING
00459       double pre      = 0.;                 // time spent before the first active module
00460       double inter    = 0.;                 // time spent between active modules
00461       double post     = 0.;                 // time spent after the last active module
00462 #else
00463       double overhead = 0.;                 // time spent before, between, or after modules
00464 #endif
00465       double current  = 0.;                 // time spent in modules active in the current path
00466       double total    = active;             // total per-path time, including modules already run as part of other paths
00467 
00468       size_t last_run = status.index();     // index of the last module run in this path
00469       for (size_t i = 0; i <= last_run; ++i) {
00470         ModuleInfo * module = pathinfo.modules[i];
00471         // fill the counter also for duplicate modules (to properly extract rejection information)
00472         pathinfo.dqm_module_counter->Fill(i);
00473         if (module == 0)
00474           // this is a module occurring more than once in the same path, skip it after the first occurrence
00475           continue;
00476         // fill the total time for all non-duplicate modules
00477         pathinfo.dqm_module_total->Fill(i, module->time_active);
00478         if (module->has_just_run) {
00479           // fill the active time only for module actually running in this path
00480           pathinfo.dqm_module_active->Fill(i, module->time_active);
00481           current += module->time_active;
00482         } else {
00483           total   += module->time_active;
00484         }
00485       }
00486       if (status.accept())
00487         pathinfo.dqm_module_counter->Fill(pathinfo.modules.size());
00488 
00489       if (m_is_first_module) {
00490         // no modules were active duruing this path, account all the time as overhead
00491 #ifdef FASTTIMERSERVICE_DETAILED_OVERHEAD_ACCOUNTING
00492         pre      = 0.;
00493         inter    = 0.;
00494         post     = active;
00495 #else
00496         overhead = active;
00497 #endif
00498       } else {
00499         // extract overhead information
00500 #ifdef FASTTIMERSERVICE_DETAILED_OVERHEAD_ACCOUNTING
00501         pre      = delta(m_timer_path.first, m_timer_first_module);
00502         post     = delta(m_timer_module.second, m_timer_path.second);
00503         inter    = active - pre - current - post;
00504         // take care of numeric precision and rounding errors - the timer is less precise than nanosecond resolution
00505         if (std::abs(inter) < 1e-9)
00506           inter = 0.;
00507 #else
00508         overhead = active - current;
00509         // take care of numeric precision and rounding errors - the timer is less precise than nanosecond resolution
00510         if (std::abs(overhead) < 1e-9)
00511           overhead = 0.;
00512 #endif
00513       }
00514 
00515 #ifdef FASTTIMERSERVICE_DETAILED_OVERHEAD_ACCOUNTING
00516       pathinfo.time_premodules       = pre;
00517       pathinfo.time_intermodules     = inter;
00518       pathinfo.time_postmodules      = post;
00519 #else
00520       pathinfo.time_overhead         = overhead;
00521 #endif
00522       pathinfo.time_total            = total;
00523 #ifdef FASTTIMERSERVICE_DETAILED_OVERHEAD_ACCOUNTING
00524       pathinfo.summary_premodules   += pre;
00525       pathinfo.summary_intermodules += inter;
00526       pathinfo.summary_postmodules  += post;
00527 #else
00528       pathinfo.summary_overhead     += overhead;
00529 #endif
00530       pathinfo.summary_total        += total;
00531       if (m_dqms) {
00532 #ifdef FASTTIMERSERVICE_DETAILED_OVERHEAD_ACCOUNTING
00533         pathinfo.dqm_premodules  ->Fill(pre      * 1000.);      // convert to ms
00534         pathinfo.dqm_intermodules->Fill(inter    * 1000.);      // convert to ms
00535         pathinfo.dqm_postmodules ->Fill(post     * 1000.);      // convert to ms
00536 #else
00537         pathinfo.dqm_overhead    ->Fill(overhead * 1000.);      // convert to ms
00538 #endif
00539         pathinfo.dqm_total       ->Fill(total    * 1000.);      // convert to ms
00540       }
00541     }
00542   }
00543 
00544   if (& path == m_last_path) {
00545     // this is the last path, stop and account the "all paths" counter
00546     m_timer_paths.second = m_timer_path.second;
00547     m_all_paths = delta(m_timer_paths);
00548     m_summary_all_paths += m_all_paths;
00549     if (m_dqms)
00550       m_dqm_all_paths->Fill(m_all_paths * 1000.);               // convert to ms
00551   } else if (& path == m_last_endpath) {
00552     // this is the last endpath, stop and account the "all endpaths" counter
00553     m_timer_endpaths.second = m_timer_path.second;
00554     m_all_endpaths = delta(m_timer_endpaths);
00555     m_summary_all_endpaths += m_all_endpaths;
00556     if (m_dqms)
00557       m_dqm_all_endpaths->Fill(m_all_endpaths * 1000.);         // convert to ms
00558   }
00559 
00560 }
00561 
00562 void FastTimerService::preModule(edm::ModuleDescription const & module) {
00563   // this is ever called only if m_enable_timing_modules = true
00564   assert(m_enable_timing_modules);
00565 
00566 #ifdef FASTTIMERSERVICE_DETAILED_OVERHEAD_ACCOUNTING
00567   // time each module
00568   start(m_timer_module);
00569 
00570   if (m_is_first_module) {
00571     m_is_first_module = false;
00572 
00573     // measure the time spent between the beginning of the path and the execution of the first module
00574     m_timer_first_module = m_timer_module.first;
00575   } 
00576 #else
00577   if (m_is_first_module) {
00578     m_is_first_module = false;
00579 
00580     // track the start of the first module of the path
00581     start(m_timer_module);
00582 
00583     // measure the time spent between the beginning of the path and the execution of the first module
00584     m_timer_first_module = m_timer_module.first;
00585   } else {
00586     // use the end time of the previous module (assume no inter-module overhead)
00587     m_timer_module.first = m_timer_module.second;
00588   }
00589 #endif
00590 }
00591 
00592 void FastTimerService::postModule(edm::ModuleDescription const & module) {
00593   // this is ever called only if m_enable_timing_modules = true
00594   assert(m_enable_timing_modules);
00595 
00596   // time and account each module
00597   stop(m_timer_module);
00598 
00599   ModuleMap<ModuleInfo>::iterator keyval = m_modules.find(& module);
00600   if (keyval != m_modules.end()) {
00601     double time = delta(m_timer_module);
00602     ModuleInfo & module = keyval->second;
00603     module.has_just_run    = true;
00604     module.time_active     = time;
00605     module.summary_active += time;
00606     if (m_dqms)
00607       module.dqm_active->Fill(time * 1000.);                    // convert to ms
00608   } else {
00609     // should never get here
00610     edm::LogError("FastTimerService") << "FastTimerService::postModule: unexpected module " << module.moduleLabel();
00611   }
00612 }
00613 
00614 // find the module description associated to a module, by label
00615 edm::ModuleDescription const * FastTimerService::findModuleDescription(const std::string & label) const {
00616   // no descriptions are associated to an empty label
00617   if (label.empty())
00618     return 0;
00619 
00620   // fix the name of negated or ignored modules
00621   std::string const & target = (label[0] == '!' or label[0] == '-') ? label.substr(1) : label;
00622 
00623   BOOST_FOREACH(ModuleMap<ModuleInfo>::value_type const & keyval, m_modules) {
00624     if (keyval.first == 0) {
00625       // 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
00626       edm::LogError("FastTimerService") << "FastTimerService::findModuleDescription: invalid entry detected in ModuleMap<ModuleInfo> m_modules, skipping";
00627       continue;
00628     }
00629     if (keyval.first->moduleLabel() == target) {
00630       return keyval.first;
00631     }
00632   }
00633   // not found
00634   return 0;
00635 }
00636 
00637 // associate to a path all the modules it contains
00638 void FastTimerService::fillPathMap(std::string const & name, std::vector<std::string> const & modules) {
00639   std::vector<ModuleInfo *> & pathmap = m_paths[name].modules;
00640   pathmap.reserve( modules.size() );
00641   std::tr1::unordered_set<edm::ModuleDescription const *> pool;        // keep track of inserted modules
00642   BOOST_FOREACH( std::string const & module, modules) {
00643     edm::ModuleDescription const * md = findModuleDescription(module);
00644     if (md == 0) {
00645       // no matching module was found
00646       pathmap.push_back( 0 );
00647     } else if (pool.insert(md).second) {
00648       // new module
00649       pathmap.push_back( & m_modules[md] );
00650     } else {
00651       // duplicate module
00652       pathmap.push_back( 0 );
00653     }
00654   }
00655 }