CMS 3D CMS Logo

Timing.cc
Go to the documentation of this file.
1 // -*- C++ -*-
2 //
3 // Package: Services
4 // Class : Timing
5 //
6 // Implementation:
7 //
8 // Original Author: Jim Kowalkowski
9 //
10 
12 
26 
27 #include <iostream>
28 #include <sstream>
29 #include <sys/resource.h>
30 #include <sys/time.h>
31 #include <atomic>
32 
33 namespace edm {
34 
35  namespace service {
36  class Timing : public TimingServiceBase {
37  public:
39  ~Timing() override;
40 
41  static void fillDescriptions(edm::ConfigurationDescriptions & descriptions);
42 
43  void addToCPUTime(double iTime) override;
44  double getTotalCPU() const override;
45 
46  private:
47 
48  void postBeginJob();
49  void postEndJob();
50 
51  void preEvent(StreamContext const&);
52  void postEvent(StreamContext const&);
53 
55 
58 
59  void preSourceLumi();
60  void postSourceLumi();
61 
62  void preSourceRun();
63  void postSourceRun();
64 
65  void preOpenFile(std::string const&, bool);
66  void postOpenFile(std::string const&, bool);
67 
68  void preModule(ModuleDescription const& md);
69  void postModule(ModuleDescription const& md);
70 
73 
76 
77  double postCommon() const;
78 
79  double curr_job_time_; // seconds
80  double curr_job_cpu_; // seconds
81  std::atomic<double> extra_job_cpu_; //seconds
82  //use last run time for determining end of processing
83  std::atomic<double> last_run_time_;
84  std::atomic<double> last_run_cpu_;
85  std::vector<double> curr_events_time_; // seconds
88  double threshold_;
89  //
90  // Min Max and total event times for each Stream.
91  // Used for summary at end of job
92  std::vector<double> max_events_time_; // seconds
93  std::vector<double> min_events_time_; // seconds
94  std::vector<double> sum_events_time_;
95  std::atomic<unsigned long> total_event_count_;
96  unsigned int nStreams_;
97  unsigned int nThreads_;
98  };
99  }
100 }
101 
102 namespace edm {
103  namespace service {
104 
105  static std::string d2str(double d) {
106  std::stringstream t;
107  t << d;
108  return t.str();
109  }
110 
111  static std::string ui2str(unsigned int i) {
112  std::stringstream t;
113  t << i;
114  return t.str();
115  }
116 
117 
118  static double getTime() {
119  struct timeval t;
120  if(gettimeofday(&t, nullptr) < 0)
121  throw cms::Exception("SysCallFailed", "Failed call to gettimeofday");
122  return static_cast<double>(t.tv_sec) + (static_cast<double>(t.tv_usec) * 1E-6);
123  }
124 
125  static double getCPU() {
126  struct rusage usage;
127  getrusage(RUSAGE_SELF, &usage);
128 
129  double totalCPUTime = 0.0;
130  // User code
131  totalCPUTime = (double)usage.ru_utime.tv_sec + (double(usage.ru_utime.tv_usec) * 1E-6);
132  // System functions
133  totalCPUTime += (double)usage.ru_stime.tv_sec + (double(usage.ru_stime.tv_usec) * 1E-6);
134 
135  // Additionally, add in CPU usage from our child processes.
136  getrusage(RUSAGE_CHILDREN, &usage);
137  totalCPUTime += (double)usage.ru_utime.tv_sec + (double(usage.ru_utime.tv_usec) * 1E-6);
138  totalCPUTime += (double)usage.ru_stime.tv_sec + (double(usage.ru_stime.tv_usec) * 1E-6);
139 
140  return totalCPUTime;
141  }
142 
143  //NOTE: We use a per thread stack for module times since unscheduled
144  // exectuion or tbb task spawning can cause a module to run on the
145  // same thread as an already running module
146  static
147  std::vector<double>& moduleTimeStack() {
148  static thread_local std::vector<double> s_stack;
149  return s_stack;
150  }
151 
152  static
153  double popStack() {
154  auto& modStack = moduleTimeStack();
155  assert(!modStack.empty());
156  double curr_module_time = modStack.back();
157  modStack.pop_back();
158  double t = getTime() - curr_module_time;
159  return t;
160  }
161 
162  static
163  void pushStack() {
164  auto& modStack = moduleTimeStack();
165  modStack.push_back(getTime());
166  }
167 
168  Timing::Timing(ParameterSet const& iPS, ActivityRegistry& iRegistry) :
169  curr_job_time_(0.),
170  curr_job_cpu_(0.),
171  extra_job_cpu_(0.0),
172  last_run_time_(0.0),
173  last_run_cpu_(0.0),
175  summary_only_(iPS.getUntrackedParameter<bool>("summaryOnly")),
176  report_summary_(iPS.getUntrackedParameter<bool>("useJobReport")),
177  threshold_(iPS.getUntrackedParameter<double>("excessiveTimeThreshold")),
180  total_event_count_(0) {
181  iRegistry.watchPostBeginJob(this, &Timing::postBeginJob);
182  iRegistry.watchPostEndJob(this, &Timing::postEndJob);
183 
184  iRegistry.watchPreEvent(this, &Timing::preEvent);
185  iRegistry.watchPostEvent(this, &Timing::postEvent);
186 
187  bool checkThreshold = true;
188  if (threshold_ <= 0.0) {
189  //we need to ignore the threshold check
191  checkThreshold = false;
192  }
193 
194  if( (not summary_only_) || (checkThreshold) ) {
197  }
198  if(checkThreshold) {
201 
202  iRegistry.watchPreSourceLumi(this, &Timing::preSourceLumi);
204 
205  iRegistry.watchPreSourceRun(this, &Timing::preSourceRun);
206  iRegistry.watchPostSourceRun(this, &Timing::postSourceRun);
207 
208  iRegistry.watchPreOpenFile(this, &Timing::preOpenFile);
209  iRegistry.watchPostOpenFile(this, &Timing::postOpenFile);
210 
213 
216 
217  iRegistry.watchPreModuleBeginJob(this, &Timing::preModule);
219 
220  iRegistry.watchPreModuleEndJob(this, &Timing::preModule);
221  iRegistry.watchPostModuleEndJob(this, &Timing::postModule);
222 
227 
232 
237 
242 
245  }
246 
247  iRegistry.preallocateSignal_.connect([this](service::SystemBounds const& iBounds){
248  nStreams_ = iBounds.maxNumberOfStreams();
249  nThreads_ = iBounds.maxNumberOfThreads();
250  curr_events_time_.resize(nStreams_,0.);
251  sum_events_time_.resize(nStreams_,0.);
252  max_events_time_.resize(nStreams_,0.);
253  min_events_time_.resize(nStreams_,1.E6);
254 
255  });
256 
257  iRegistry.postGlobalEndRunSignal_.connect([this](edm::GlobalContext const&) {
259  last_run_cpu_ = getCPU();
260  });
261  }
262 
264  }
265 
266  void Timing::addToCPUTime(double iTime) {
267  //For accounting purposes we effectively can say we started earlier
268  double expected = extra_job_cpu_.load();
269  while( not extra_job_cpu_.compare_exchange_strong(expected,expected+iTime) ) {}
270  }
271 
272  double Timing::getTotalCPU() const {
273  return getCPU();
274  }
275 
278  desc.addUntracked<bool>("summaryOnly", false)->setComment(
279  "If 'true' do not report timing for each event");
280  desc.addUntracked<bool>("useJobReport", true)->setComment(
281  "If 'true' write summary information to JobReport");
282  desc.addUntracked<double>("excessiveTimeThreshold", 0.)->setComment(
283  "Amount of time in seconds before reporting a module or source has taken excessive time. A value of 0.0 turns off this reporting.");
284  descriptions.add("Timing", desc);
285  descriptions.setComment(
286  "This service reports the time it takes to run each module in a job.");
287  }
288 
291  curr_job_cpu_ = getCPU();
292 
293  if(not summary_only_) {
294  LogImportant("TimeReport")
295  << "TimeReport> Report activated" << "\n"
296  << "TimeReport> Report columns headings for events: "
297  << "eventnum runnum timetaken\n"
298  << "TimeReport> Report columns headings for modules: "
299  << "eventnum runnum modulelabel modulename timetakeni\n"
300  << "TimeReport> JobTime=" << curr_job_time_ << " JobCPU=" << curr_job_cpu_ << "\n";
301  }
302  }
303 
305  const double job_end_time =getTime();
306  const double job_end_cpu =getCPU();
307  double total_job_time = job_end_time - jobStartTime();
308 
309  double total_job_cpu = job_end_cpu+extra_job_cpu_;
310 
311  const double total_initialization_time = curr_job_time_ - jobStartTime();
312  const double total_initialization_cpu = curr_job_cpu_;
313 
314  if( 0.0 == jobStartTime()) {
315  //did not capture beginning time
316  total_job_time =job_end_time - curr_job_time_;
317  total_job_cpu =job_end_cpu + extra_job_cpu_ - curr_job_cpu_ ;
318  }
319 
320  double min_event_time = *(std::min_element(min_events_time_.begin(),
321  min_events_time_.end()));
322  double max_event_time = *(std::max_element(max_events_time_.begin(),
323  max_events_time_.end()));
324 
325  auto total_loop_time = last_run_time_ - curr_job_time_;
326  auto total_loop_cpu = last_run_cpu_ + extra_job_cpu_ - curr_job_cpu_;
327 
328  if(last_run_time_ == 0.0) {
329  total_loop_time = 0.0;
330  total_loop_cpu = 0.0;
331  }
332 
333  double sum_all_events_time = 0;
334  for(auto t : sum_events_time_) { sum_all_events_time += t; }
335 
336  double average_event_time = 0.0;
337  if(total_event_count_ != 0) {
338  average_event_time = sum_all_events_time / total_event_count_;
339  }
340 
341  double event_throughput = 0.0;
342  if(total_loop_time != 0.0) {
343  event_throughput = total_event_count_ / total_loop_time;
344  }
345 
346  LogImportant("TimeReport")
347  << "TimeReport> Time report complete in "
348  << total_job_time << " seconds"
349  << "\n"
350  << " Time Summary: \n"
351  << " - Min event: " << min_event_time << "\n"
352  << " - Max event: " << max_event_time << "\n"
353  << " - Avg event: " << average_event_time << "\n"
354  << " - Total loop: " << total_loop_time <<"\n"
355  << " - Total init: " << total_initialization_time <<"\n"
356  << " - Total job: " << total_job_time << "\n"
357  << " Event Throughput: "<< event_throughput <<" ev/s\n"
358  << " CPU Summary: \n"
359  << " - Total loop: " << total_loop_cpu << "\n"
360  << " - Total init: " << total_initialization_cpu <<"\n"
361  << " - Total extra: " << extra_job_cpu_ << "\n"
362  << " - Total job: " << total_job_cpu << "\n";
363 
364 
365  if(report_summary_) {
366  Service<JobReport> reportSvc;
367  std::map<std::string, std::string> reportData;
368 
369  reportData.insert(std::make_pair("MinEventTime", d2str(min_event_time)));
370  reportData.insert(std::make_pair("MaxEventTime", d2str(max_event_time)));
371  reportData.insert(std::make_pair("AvgEventTime", d2str(average_event_time)));
372  reportData.insert(std::make_pair("EventThroughput", d2str(event_throughput)));
373  reportData.insert(std::make_pair("TotalJobTime", d2str(total_job_time)));
374  reportData.insert(std::make_pair("TotalJobCPU", d2str(total_job_cpu)));
375  reportData.insert(std::make_pair("TotalLoopTime", d2str(total_loop_time)));
376  reportData.insert(std::make_pair("TotalLoopCPU", d2str(total_loop_cpu)));
377  reportData.insert(std::make_pair("TotalInitTime", d2str(total_initialization_time)));
378  reportData.insert(std::make_pair("TotalInitCPU", d2str(total_initialization_cpu)));
379  reportData.insert(std::make_pair("NumberOfStreams",ui2str(nStreams_)));
380  reportData.insert(std::make_pair("NumberOfThreads",ui2str(nThreads_)));
381  reportSvc->reportPerformanceSummary("Timing", reportData);
382  }
383  }
384 
385  void Timing::preEvent(StreamContext const& iStream) {
386  auto index = iStream.streamID().value();
388  }
389 
390  void Timing::postEvent(StreamContext const& iStream) {
391  auto index = iStream.streamID().value();
392 
393  double curr_event_time = getTime() - curr_events_time_[index];
394  sum_events_time_[index] +=curr_event_time;
395 
396  if(not summary_only_) {
397  auto const & eventID = iStream.eventID();
398  LogPrint("TimeEvent")
399  << "TimeEvent> "
400  << eventID.event() << " "
401  << eventID.run() << " "
402  << curr_event_time ;
403  }
404  if(curr_event_time > max_events_time_[index]) max_events_time_[index] = curr_event_time;
405  if(curr_event_time < min_events_time_[index]) min_events_time_[index] = curr_event_time;
407  }
408 
409  void Timing::postModuleEvent(StreamContext const& iStream, ModuleCallingContext const& iModule) {
410  auto const & eventID = iStream.eventID();
411  auto const & desc = *(iModule.moduleDescription());
412  double t = postCommon();
413  if ( not summary_only_) {
414  LogPrint("TimeModule") << "TimeModule> "
415  << eventID.event() << " "
416  << eventID.run() << " "
417  << desc.moduleLabel() << " "
418  << desc.moduleName() << " "
419  << t;
420  }
421  }
422 
424  pushStack();
425  }
426 
428  postCommon();
429  }
430 
432  pushStack();
433  }
434 
436  postCommon();
437  }
438 
440  pushStack();
441  }
442 
444  postCommon();
445  }
446 
447  void Timing::preOpenFile(std::string const& lfn, bool b) {
448  pushStack();
449  }
450 
451  void Timing::postOpenFile(std::string const& lfn, bool b) {
452  postCommon();
453  }
454 
455  void
457  pushStack();
458  }
459 
460  void
462  postCommon();
463  }
464 
465  void
467  pushStack();
468  }
469 
470  void
472  postCommon();
473  }
474 
475  void
477  pushStack();
478  }
479 
480  void
482  postCommon();
483  }
484 
485  double
487  double t = popStack();
488  if(t > threshold_) {
489  LogError("ExcessiveTime")
490  << "ExcessiveTime: Module used " << t
491  << " seconds of time which exceeds the error threshold configured in the Timing Service of "
492  << threshold_ << " seconds.";
493  }
494  return t;
495  }
496  }
497 }
498 
500 
void watchPostModuleGlobalEndLumi(PostModuleGlobalEndLumi::slot_type const &iSlot)
void watchPostModuleConstruction(PostModuleConstruction::slot_type const &iSlot)
std::vector< double > sum_events_time_
Definition: Timing.cc:94
unsigned int maxNumberOfThreads() const
Definition: SystemBounds.h:46
void watchPreModuleGlobalBeginRun(PreModuleGlobalBeginRun::slot_type const &iSlot)
void setComment(std::string const &value)
void watchPreEvent(PreEvent::slot_type const &iSlot)
double curr_job_time_
Definition: Timing.cc:79
std::atomic< double > last_run_cpu_
Definition: Timing.cc:84
#define DEFINE_FWK_SERVICE_MAKER(concrete, maker)
Definition: ServiceMaker.h:117
std::vector< double > max_events_time_
Definition: Timing.cc:92
ParameterDescriptionBase * addUntracked(U const &iLabel, T const &value)
void watchPostEndJob(PostEndJob::slot_type const &iSlot)
std::vector< double > curr_events_time_
Definition: Timing.cc:85
void watchPreModuleEvent(PreModuleEvent::slot_type const &iSlot)
void watchPreModuleConstruction(PreModuleConstruction::slot_type const &iSlot)
void watchPostEvent(PostEvent::slot_type const &iSlot)
double getTotalCPU() const override
Definition: Timing.cc:272
void preModule(ModuleDescription const &md)
Definition: Timing.cc:456
void watchPreSourceConstruction(PreSourceConstruction::slot_type const &iSlot)
static double getCPU()
Definition: Timing.cc:125
void watchPostSourceConstruction(PostSourceConstruction::slot_type const &iSlot)
void watchPreEventReadFromSource(PreEventReadFromSource::slot_type const &iSlot)
void watchPostModuleEvent(PostModuleEvent::slot_type const &iSlot)
void watchPostModuleGlobalBeginLumi(PostModuleGlobalBeginLumi::slot_type const &iSlot)
void watchPostModuleStreamEndLumi(PostModuleStreamEndLumi::slot_type const &iSlot)
void postEvent(StreamContext const &)
Definition: Timing.cc:390
void preModuleStream(StreamContext const &, ModuleCallingContext const &)
Definition: Timing.cc:476
double curr_job_cpu_
Definition: Timing.cc:80
void watchPostModuleStreamBeginRun(PostModuleStreamBeginRun::slot_type const &iSlot)
void watchPostSourceEvent(PostSourceEvent::slot_type const &iSlot)
edm::serviceregistry::AllArgsMaker< edm::TimingServiceBase, Timing > TimingMaker
Definition: Timing.cc:501
void watchPreModuleGlobalEndRun(PreModuleGlobalEndRun::slot_type const &iSlot)
unsigned int nThreads_
Definition: Timing.cc:97
void preOpenFile(std::string const &, bool)
Definition: Timing.cc:447
unsigned int nStreams_
Definition: Timing.cc:96
void preModuleGlobal(GlobalContext const &, ModuleCallingContext const &)
Definition: Timing.cc:466
void postModule(ModuleDescription const &md)
Definition: Timing.cc:461
static void pushStack()
Definition: Timing.cc:163
Preallocate preallocateSignal_
signal is emitted before beginJob
unsigned int maxNumberOfStreams() const
Definition: SystemBounds.h:43
void watchPreOpenFile(PreOpenFile::slot_type const &iSlot)
void postModuleStream(StreamContext const &, ModuleCallingContext const &)
Definition: Timing.cc:481
void watchPostSourceRun(PostSourceRun::slot_type const &iSlot)
Timing(ParameterSet const &, ActivityRegistry &)
Definition: Timing.cc:168
void watchPreSourceLumi(PreSourceLumi::slot_type const &iSlot)
ModuleDescription const * moduleDescription() const
void postModuleEvent(StreamContext const &, ModuleCallingContext const &)
Definition: Timing.cc:409
std::atomic< double > last_run_time_
Definition: Timing.cc:83
void watchPreModuleEndJob(PreModuleEndJob::slot_type const &iSlot)
static void fillDescriptions(edm::ConfigurationDescriptions &descriptions)
Definition: Timing.cc:276
~Timing() override
Definition: Timing.cc:263
void watchPreSourceRun(PreSourceRun::slot_type const &iSlot)
void preSourceLumi()
Definition: Timing.cc:431
void watchPreModuleBeginJob(PreModuleBeginJob::slot_type const &iSlot)
static double jobStartTime()
void postSourceRun()
Definition: Timing.cc:443
void watchPreModuleGlobalBeginLumi(PreModuleGlobalBeginLumi::slot_type const &iSlot)
void watchPostModuleStreamEndRun(PostModuleStreamEndRun::slot_type const &iSlot)
StreamID const & streamID() const
Definition: StreamContext.h:57
static std::string ui2str(unsigned int i)
Definition: Timing.cc:111
void watchPreModuleStreamBeginLumi(PreModuleStreamBeginLumi::slot_type const &iSlot)
void setComment(std::string const &value)
unsigned int value() const
Definition: StreamID.h:46
void watchPostSourceLumi(PostSourceLumi::slot_type const &iSlot)
void watchPostModuleGlobalEndRun(PostModuleGlobalEndRun::slot_type const &iSlot)
void watchPostModuleStreamBeginLumi(PostModuleStreamBeginLumi::slot_type const &iSlot)
std::atomic< unsigned long > total_event_count_
Definition: Timing.cc:95
void watchPreModuleStreamEndLumi(PreModuleStreamEndLumi::slot_type const &iSlot)
void watchPreModuleStreamBeginRun(PreModuleStreamBeginRun::slot_type const &iSlot)
static std::vector< double > & moduleTimeStack()
Definition: Timing.cc:147
void addToCPUTime(double iTime) override
Definition: Timing.cc:266
double b
Definition: hdecay.h:120
static std::string d2str(double d)
void add(std::string const &label, ParameterSetDescription const &psetDescription)
void watchPostOpenFile(PostOpenFile::slot_type const &iSlot)
double postCommon() const
Definition: Timing.cc:486
PostGlobalEndRun postGlobalEndRunSignal_
void postSourceLumi()
Definition: Timing.cc:435
void postModuleGlobal(GlobalContext const &, ModuleCallingContext const &)
Definition: Timing.cc:471
HLT enums.
void watchPreModuleStreamEndRun(PreModuleStreamEndRun::slot_type const &iSlot)
void postOpenFile(std::string const &, bool)
Definition: Timing.cc:451
static double getTime()
Definition: Timing.cc:118
void watchPostModuleBeginJob(PostModuleBeginJob::slot_type const &iSlot)
void postSourceEvent(StreamID)
Definition: Timing.cc:427
void watchPostEventReadFromSource(PostEventReadFromSource::slot_type const &iSlot)
void watchPostModuleGlobalBeginRun(PostModuleGlobalBeginRun::slot_type const &iSlot)
EventID const & eventID() const
Definition: StreamContext.h:59
void watchPreSourceEvent(PreSourceEvent::slot_type const &iSlot)
std::atomic< double > extra_job_cpu_
Definition: Timing.cc:81
static double popStack()
Definition: Timing.cc:153
void preSourceEvent(StreamID)
Definition: Timing.cc:423
void watchPostModuleEndJob(PostModuleEndJob::slot_type const &iSlot)
void connect(U iFunc)
Definition: Signal.h:63
void preEvent(StreamContext const &)
Definition: Timing.cc:385
void watchPreModuleGlobalEndLumi(PreModuleGlobalEndLumi::slot_type const &iSlot)
std::vector< double > min_events_time_
Definition: Timing.cc:93
void watchPostBeginJob(PostBeginJob::slot_type const &iSlot)
convenience function for attaching to signal