CMS 3D CMS Logo

/data/refman/pasoursint/CMSSW_5_3_3/src/HLTrigger/Timer/interface/FastTimerService.h

Go to the documentation of this file.
00001 #ifndef FastTimerService_h
00002 #define FastTimerService_h
00003 
00004 //system headers
00005 #ifdef __linux
00006 #include <time.h>
00007 #else
00008 typedef int clockid_t;
00009 #endif
00010 
00011 // C++ headers
00012 #include <cmath>
00013 #include <string>
00014 #include <map>
00015 #include <tr1/unordered_map>
00016 
00017 // CMSSW headers
00018 #include "FWCore/ServiceRegistry/interface/ActivityRegistry.h"
00019 #include "FWCore/ServiceRegistry/interface/Service.h"
00020 #include "FWCore/ParameterSet/interface/ParameterSet.h"
00021 #include "FWCore/Framework/interface/TriggerNamesService.h"
00022 #include "FWCore/MessageLogger/interface/MessageLogger.h"
00023 #include "DataFormats/Common/interface/HLTPathStatus.h"
00024 #include "DataFormats/Provenance/interface/EventID.h"
00025 #include "DataFormats/Provenance/interface/Timestamp.h"
00026 #include "DataFormats/Provenance/interface/ModuleDescription.h"
00027 #include "DQMServices/Core/interface/DQMStore.h"
00028 #include "DQMServices/Core/interface/MonitorElement.h"
00029 
00030 
00031 /*
00032 procesing time is diveded into
00033  - source
00034  - pre-event processing overhead
00035  - event processing
00036  - post-event processing overhead
00037 
00038 until lumi-processing and run-processing are taken into account, they will count as overhead
00039 
00040 event processing time is diveded into
00041  - trigger processing (from the begin of the first path to the end of the last path)
00042  - trigger overhead
00043  - endpath processing (from the begin of the first endpath to the end of the last endpath)
00044  - endpath overhead
00045 */
00046 
00047 /*
00048 Timer per-call overhead (on lxplus, SLC 5.7):
00049 
00050 Test results for "clock_gettime(CLOCK_THREAD_CPUTIME_ID, & value)"
00051  - average time per call: 340 ns
00052  - resolution:              ? ns
00053 
00054 Test results for "clock_gettime(CLOCK_PROCESS_CPUTIME_ID, & value)"
00055  - average time per call: 360 ns
00056  - resolution:              ? ns
00057 
00058 Test results for "clock_gettime(CLOCK_REALTIME, & value)"
00059  - average time per call: 320 ns
00060  - resolution:              1 us
00061 
00062 Test results for "getrusage(RUSAGE_SELF, & value)"
00063  - average time per call: 380 ns
00064  - resolution:              1 ms
00065 
00066 Test results for "gettimeofday(& value, NULL)"
00067  - average time per call:  65 ns
00068  - resolution:              1 us
00069 
00070 Assuming an HLT process with ~2500 modules and ~500 paths, tracking each step
00071 with clock_gettime(CLOCK_THREAD_CPUTIME_ID) gives a per-event overhead of 2 ms
00072 
00073 Detailed informations on different timers can be extracted running $CMSSW_RELEASE_BASE/test/$SCRAM_ARCH/testTimer .
00074 */
00075 
00076 
00077 class FastTimerService {
00078 public:
00079   FastTimerService(const edm::ParameterSet &, edm::ActivityRegistry & );
00080   ~FastTimerService();
00081 
00082   // query the current module/path/event
00083   // Note: these functions incur in a "per-call timer overhead" (see above), currently of the order of 340ns
00084   double currentModuleTime() const;         // return the time spent since the last preModule() event
00085   double currentPathTime() const;           // return the time spent since the last preProcessPath() event
00086   double currentEventTime() const;          // return the time spent since the last preProcessEvent() event
00087 
00088   // query the time spent in a module/path the last time it has run
00089   double queryModuleTime(const edm::ModuleDescription &) const;
00090   double queryPathTime(const std::string &) const;
00091 
00092   // query the time spent in the current (or last) event's
00093   //  - source        (available during event processing)
00094   //  - all paths     (available during endpaths)
00095   //  - all endpaths  (available after all endpaths have run, usually returns the last event's value)
00096   //  - processing    (available after the event has been processed, usually returns the last event's value)
00097   double querySourceTime() const;
00098   double queryPathsTime() const;
00099   double queryEndPathsTime() const;
00100   double queryEventTime() const;
00101 
00102   // try to assess the overhead which may not be included in the source, paths and event timers
00103   double queryPreSourceOverhead() const;    // time spent after the previous event's postProcessEvent and this event's preSource
00104   double queryPreEventOverhead() const;     // time spent after this event's postSource and preProcessEvent
00105   double queryPreEndPathsOverhead() const;  // time spent after the last path's postProcessPath and the first endpath's preProcessPath
00106 
00107 
00108 private:
00109   void postBeginJob();
00110   void postEndJob();
00111   void preModuleBeginJob( edm::ModuleDescription const & );
00112   void preProcessEvent( edm::EventID const &, edm::Timestamp const & );
00113   void postProcessEvent( edm::Event const &, edm::EventSetup const & );
00114   void preSource();
00115   void postSource();
00116   void prePathBeginRun( std::string const & );
00117   void preProcessPath(  std::string const & );
00118   void postProcessPath( std::string const &, edm::HLTPathStatus const & );
00119   void preModule(  edm::ModuleDescription const & );
00120   void postModule( edm::ModuleDescription const & );
00121 
00122   // needed for the DAQ when reconfiguring between runs
00123   void reset();
00124 
00125 private:
00126 
00127   struct ModuleInfo {
00128     double                      time_active;        // per-event timer: time actually spent in this module
00129     double                      summary_active;
00130     TH1F *                      dqm_active;
00131     bool                        has_just_run;       // flag sed to check if a module was active inside a particular path, or not
00132 
00133   public:
00134     ModuleInfo() :
00135       time_active(0.),
00136       summary_active(0.),
00137       dqm_active(0),
00138       has_just_run(false)
00139     { }
00140 
00141     ~ModuleInfo() {
00142       reset();
00143     }
00144 
00145     // reset the timers and DQM plots
00146     void reset() {
00147       time_active = 0.;
00148       summary_active = 0.;
00149       // the DAQ destroys and re-creates the DQM and DQMStore services at each reconfigure, so we don't need to clean them up
00150       dqm_active = 0;
00151       has_just_run = false;
00152     }
00153   };
00154 
00155   struct PathInfo {
00156     std::vector<ModuleInfo *>   modules;            // list of all modules contributing to the path (duplicate modules stored as null pointers)
00157     double                      time_active;        // per-event timer: time actually spent in this path
00158 #ifdef FASTTIMERSERVICE_DETAILED_OVERHEAD_ACCOUNTING
00159     double                      time_premodules;    // per-event timer: time spent between "begin path" and the first "begin module"
00160     double                      time_intermodules;  // per-event timer: time spent between modules
00161     double                      time_postmodules;   // per-event timer: time spent between the last "end module" and "end path"
00162 #else
00163     double                      time_overhead;      // per-event timer: sum of time_premodules, time_intermodules, time_postmodules
00164 #endif
00165     double                      time_total;         // per-event timer: sum of the time spent in all modules which would have run in this path (plus overhead)
00166     double                      summary_active;
00167 #ifdef FASTTIMERSERVICE_DETAILED_OVERHEAD_ACCOUNTING
00168     double                      summary_premodules;
00169     double                      summary_intermodules;
00170     double                      summary_postmodules;
00171 #else
00172     double                      summary_overhead;
00173 #endif
00174     double                      summary_total;
00175     TH1F *                      dqm_active;
00176 #ifdef FASTTIMERSERVICE_DETAILED_OVERHEAD_ACCOUNTING
00177     TH1F *                      dqm_premodules;
00178     TH1F *                      dqm_intermodules;
00179     TH1F *                      dqm_postmodules;
00180 #else
00181     TH1F *                      dqm_overhead;
00182 #endif
00183     TH1F *                      dqm_total;
00184     TH1F *                      dqm_module_counter;     // for each module in the path, track how many times it ran
00185     TH1F *                      dqm_module_active;      // for each module in the path, track the active time spent 
00186     TH1F *                      dqm_module_total;       // for each module in the path, track the total time spent 
00187 
00188   public:
00189     PathInfo() :
00190       modules(),
00191       time_active(0.),
00192 #ifdef FASTTIMERSERVICE_DETAILED_OVERHEAD_ACCOUNTING
00193       time_premodules(0.),
00194       time_intermodules(0.),
00195       time_postmodules(0.),
00196 #else
00197       time_overhead(0.),
00198 #endif
00199       time_total(0.),
00200       summary_active(0.),
00201 #ifdef FASTTIMERSERVICE_DETAILED_OVERHEAD_ACCOUNTING
00202       summary_premodules(0.),
00203       summary_intermodules(0.),
00204       summary_postmodules(0.),
00205 #else
00206       summary_overhead(0.),
00207 #endif
00208       summary_total(0.),
00209       dqm_active(0),
00210 #ifdef FASTTIMERSERVICE_DETAILED_OVERHEAD_ACCOUNTING
00211       dqm_premodules(0),
00212       dqm_intermodules(0),
00213       dqm_postmodules(0),
00214 #else
00215       dqm_overhead(0),
00216 #endif
00217       dqm_total(0),
00218       dqm_module_counter(0),
00219       dqm_module_active(0),
00220       dqm_module_total(0)
00221     { }
00222 
00223     ~PathInfo() {
00224       reset();
00225     }
00226 
00227     // reset the timers and DQM plots
00228     void reset() {
00229       modules.clear();
00230       time_active = 0.;
00231 #ifdef FASTTIMERSERVICE_DETAILED_OVERHEAD_ACCOUNTING
00232       time_premodules = 0.;
00233       time_intermodules = 0.;
00234       time_postmodules = 0.;
00235 #else
00236       time_overhead = 0.;
00237 #endif
00238       time_total = 0.;
00239       summary_active = 0.;
00240 #ifdef FASTTIMERSERVICE_DETAILED_OVERHEAD_ACCOUNTING
00241       summary_premodules = 0.;
00242       summary_intermodules = 0.;
00243       summary_postmodules = 0.;
00244 #else
00245       summary_overhead = 0.;
00246 #endif
00247       summary_total = 0.;
00248 
00249       // the DAQ destroys and re-creates the DQM and DQMStore services at each reconfigure, so we don't need to clean them up
00250       dqm_active = 0;
00251 #ifdef FASTTIMERSERVICE_DETAILED_OVERHEAD_ACCOUNTING
00252       dqm_premodules = 0;
00253       dqm_intermodules = 0;
00254       dqm_postmodules = 0;
00255 #else
00256       dqm_overhead = 0;
00257 #endif
00258       dqm_total = 0;
00259       dqm_module_counter = 0;
00260       dqm_module_active = 0;
00261       dqm_module_total = 0;
00262     }
00263   };
00264 
00265   template <typename T> class PathMap   : public std::tr1::unordered_map<std::string, T> {};
00266   template <typename T> class ModuleMap : public std::tr1::unordered_map<edm::ModuleDescription const *, T> {};
00267 
00268   // configuration
00269   const clockid_t                               m_timer_id;             // the default is to use CLOCK_THREAD_CPUTIME_ID, unless useRealTimeClock is set, which will use CLOCK_REALTIME
00270   bool                                          m_is_cpu_bound;         // if the process is not bound to a single CPU, per-thread or per-process measuerements may be unreliable
00271   const bool                                    m_enable_timing_modules;
00272   const bool                                    m_enable_timing_paths;
00273   const bool                                    m_enable_timing_summary;
00274   const bool                                    m_enable_dqm;
00275   const bool                                    m_enable_dqm_bymodule;
00276   const bool                                    m_enable_dqm_bylumi;
00277 
00278   // dqm configuration
00279   const bool                                    m_skip_first_path;
00280   const double                                  m_dqm_eventtime_range;
00281   const double                                  m_dqm_eventtime_resolution;
00282   const double                                  m_dqm_pathtime_range;
00283   const double                                  m_dqm_pathtime_resolution;
00284   const double                                  m_dqm_moduletime_range;
00285   const double                                  m_dqm_moduletime_resolution;
00286   std::string                                   m_dqm_path;
00287 
00288   // job configuration and caching
00289   std::string const *                           m_first_path;           // the framework does not provide a pre-paths or pre-endpaths signal,
00290   std::string const *                           m_last_path;            // so we emulate them keeping track of the first and last path and endpath
00291   std::string const *                           m_first_endpath;
00292   std::string const *                           m_last_endpath;
00293   bool                                          m_is_first_module;      // helper to measure the time spent between the beginning of the path and the execution of the first module
00294 
00295   // per-event accounting
00296   double                                        m_event;
00297   double                                        m_source;
00298   double                                        m_all_paths;
00299   double                                        m_all_endpaths;
00300 
00301   // per-job summary
00302   unsigned int                                  m_summary_events;       // number of events
00303   double                                        m_summary_event;
00304   double                                        m_summary_source;
00305   double                                        m_summary_all_paths;
00306   double                                        m_summary_all_endpaths;
00307 
00308   // DQM
00309   DQMStore *                                    m_dqms;
00310   TH1F *                                        m_dqm_event;
00311   TH1F *                                        m_dqm_source;
00312   TH1F *                                        m_dqm_all_paths;
00313   TH1F *                                        m_dqm_all_endpaths;
00314 
00315   // per-path and per-module accounting
00316   PathInfo *                                    m_current_path;
00317   PathMap<PathInfo>                             m_paths;
00318   ModuleMap<ModuleInfo>                         m_modules;              // this assumes that ModuleDescription are stored in the same object through the whole job,
00319                                                                         // which is true only *after* the edm::Worker constructors have run
00320   std::vector<PathInfo *>                       m_cache_paths;
00321   std::vector<ModuleInfo *>                     m_cache_modules;
00322 
00323 
00324   // timers
00325   std::pair<struct timespec, struct timespec>   m_timer_event;          // track time spent in each event
00326   std::pair<struct timespec, struct timespec>   m_timer_source;         // track time spent in the source
00327   std::pair<struct timespec, struct timespec>   m_timer_paths;          // track time spent in all paths
00328   std::pair<struct timespec, struct timespec>   m_timer_endpaths;       // track time spent in all endpaths
00329   std::pair<struct timespec, struct timespec>   m_timer_path;           // track time spent in each path
00330   std::pair<struct timespec, struct timespec>   m_timer_module;         // track time spent in each module
00331   struct timespec                               m_timer_first_module;   // record the start of the first active module in a path, if any
00332 
00333   void gettime(struct timespec & stamp)
00334   {
00335 #if defined __linux
00336     clock_gettime(m_timer_id, & stamp);
00337 #elif defined __APPLE__ && defined __MACH__
00338     // implement here an OS X version
00339 #else
00340     // unsupported on any other platform
00341 #endif
00342   }
00343 
00344   void start(std::pair<struct timespec, struct timespec> & times)
00345   {
00346     gettime(times.first);
00347   }
00348 
00349   void stop(std::pair<struct timespec, struct timespec> & times)
00350   {
00351     gettime(times.second);
00352   }
00353 
00354   static
00355   double delta(const struct timespec & first, const struct timespec & second)
00356   {
00357     if (second.tv_nsec > first.tv_nsec)
00358       return (double) (second.tv_sec - first.tv_sec) + (double) (second.tv_nsec - first.tv_nsec) / (double) 1e9;
00359     else
00360       return (double) (second.tv_sec - first.tv_sec) - (double) (first.tv_nsec - second.tv_nsec) / (double) 1e9;
00361   }
00362 
00363   static
00364   double delta(const std::pair<struct timespec, struct timespec> & times)
00365   {
00366     return delta(times.first, times.second);
00367   }
00368 
00369   // find the module description associated to a module, by name
00370   edm::ModuleDescription const * findModuleDescription(const std::string & module) const;
00371 
00372   // associate to a path all the modules it contains
00373   void fillPathMap(std::string const & name, std::vector<std::string> const & modules);
00374 
00375 };
00376 
00377 #endif // ! FastTimerService_h