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();
40 
41  static void fillDescriptions(edm::ConfigurationDescriptions & descriptions);
42 
43  virtual void addToCPUTime(StreamID id, double iTime) override;
44  virtual 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  //use last run time for determining end of processing
82  std::atomic<double> last_run_time_;
83  std::atomic<double> last_run_cpu_;
84  std::vector<double> curr_events_time_; // seconds
87  double threshold_;
88  //
89  // Min Max and total event times for each Stream.
90  // Used for summary at end of job
91  std::vector<double> max_events_time_; // seconds
92  std::vector<double> min_events_time_; // seconds
93  std::vector<double> sum_events_time_;
94  std::atomic<unsigned long> total_event_count_;
95  unsigned int nStreams_;
96  unsigned int nThreads_;
97  };
98  }
99 }
100 
101 namespace edm {
102  namespace service {
103 
104  static std::string d2str(double d) {
105  std::stringstream t;
106  t << d;
107  return t.str();
108  }
109 
110  static std::string ui2str(unsigned int i) {
111  std::stringstream t;
112  t << i;
113  return t.str();
114  }
115 
116 
117  static double getTime() {
118  struct timeval t;
119  if(gettimeofday(&t, 0) < 0)
120  throw cms::Exception("SysCallFailed", "Failed call to gettimeofday");
121  return static_cast<double>(t.tv_sec) + (static_cast<double>(t.tv_usec) * 1E-6);
122  }
123 
124  static double getCPU() {
125  struct rusage usage;
126  getrusage(RUSAGE_SELF, &usage);
127 
128  double totalCPUTime = 0.0;
129  // User code
130  totalCPUTime = (double)usage.ru_utime.tv_sec + (double(usage.ru_utime.tv_usec) * 1E-6);
131  // System functions
132  totalCPUTime += (double)usage.ru_stime.tv_sec + (double(usage.ru_stime.tv_usec) * 1E-6);
133 
134  // Additionally, add in CPU usage from our child processes.
135  getrusage(RUSAGE_CHILDREN, &usage);
136  totalCPUTime += (double)usage.ru_utime.tv_sec + (double(usage.ru_utime.tv_usec) * 1E-6);
137  totalCPUTime += (double)usage.ru_stime.tv_sec + (double(usage.ru_stime.tv_usec) * 1E-6);
138 
139  return totalCPUTime;
140  }
141 
142  //NOTE: We use a per thread stack for module times since unscheduled
143  // exectuion or tbb task spawning can cause a module to run on the
144  // same thread as an already running module
145  static
146  std::vector<double>& moduleTimeStack() {
147  static thread_local std::vector<double> s_stack;
148  return s_stack;
149  }
150 
151  static
152  double popStack() {
153  auto& modStack = moduleTimeStack();
154  assert(modStack.size() > 0);
155  double curr_module_time = modStack.back();
156  modStack.pop_back();
157  double t = getTime() - curr_module_time;
158  return t;
159  }
160 
161  static
162  void pushStack() {
163  auto& modStack = moduleTimeStack();
164  modStack.push_back(getTime());
165  }
166 
167  Timing::Timing(ParameterSet const& iPS, ActivityRegistry& iRegistry) :
168  curr_job_time_(0.),
169  curr_job_cpu_(0.),
170  last_run_time_(0.0),
171  last_run_cpu_(0.0),
173  summary_only_(iPS.getUntrackedParameter<bool>("summaryOnly")),
174  report_summary_(iPS.getUntrackedParameter<bool>("useJobReport")),
175  threshold_(iPS.getUntrackedParameter<double>("excessiveTimeThreshold")),
178  total_event_count_(0) {
179  iRegistry.watchPostBeginJob(this, &Timing::postBeginJob);
180  iRegistry.watchPostEndJob(this, &Timing::postEndJob);
181 
182  iRegistry.watchPreEvent(this, &Timing::preEvent);
183  iRegistry.watchPostEvent(this, &Timing::postEvent);
184 
185  bool checkThreshold = true;
186  if (threshold_ <= 0.0) {
187  //we need to ignore the threshold check
189  checkThreshold = false;
190  }
191 
192  if( (not summary_only_) || (checkThreshold) ) {
195  }
196  if(checkThreshold) {
199 
200  iRegistry.watchPreSourceLumi(this, &Timing::preSourceLumi);
202 
203  iRegistry.watchPreSourceRun(this, &Timing::preSourceRun);
204  iRegistry.watchPostSourceRun(this, &Timing::postSourceRun);
205 
206  iRegistry.watchPreOpenFile(this, &Timing::preOpenFile);
207  iRegistry.watchPostOpenFile(this, &Timing::postOpenFile);
208 
211 
214 
215  iRegistry.watchPreModuleBeginJob(this, &Timing::preModule);
217 
218  iRegistry.watchPreModuleEndJob(this, &Timing::preModule);
219  iRegistry.watchPostModuleEndJob(this, &Timing::postModule);
220 
225 
230 
235 
240 
243  }
244 
245  iRegistry.preallocateSignal_.connect([this](service::SystemBounds const& iBounds){
246  nStreams_ = iBounds.maxNumberOfStreams();
247  nThreads_ = iBounds.maxNumberOfThreads();
248  curr_events_time_.resize(nStreams_,0.);
249  sum_events_time_.resize(nStreams_,0.);
250  max_events_time_.resize(nStreams_,0.);
251  min_events_time_.resize(nStreams_,1.E6);
252 
253  });
254 
255  iRegistry.postGlobalEndRunSignal_.connect([this](edm::GlobalContext const&) {
257  last_run_cpu_ = getCPU();
258  });
259  }
260 
262  }
263 
264  void Timing::addToCPUTime(StreamID id, double iTime) {
265  //For accounting purposes we effectively can say we started earlier
266  curr_job_cpu_ -= iTime;
267  }
268 
269  double Timing::getTotalCPU() const {
270  return getCPU();
271  }
272 
275  desc.addUntracked<bool>("summaryOnly", false)->setComment(
276  "If 'true' do not report timing for each event");
277  desc.addUntracked<bool>("useJobReport", true)->setComment(
278  "If 'true' write summary information to JobReport");
279  desc.addUntracked<double>("excessiveTimeThreshold", 0.)->setComment(
280  "Amount of time in seconds before reporting a module or source has taken excessive time. A value of 0.0 turns off this reporting.");
281  descriptions.add("Timing", desc);
282  descriptions.setComment(
283  "This service reports the time it takes to run each module in a job.");
284  }
285 
288  curr_job_cpu_ = getCPU();
289 
290  if(not summary_only_) {
291  LogImportant("TimeReport")
292  << "TimeReport> Report activated" << "\n"
293  << "TimeReport> Report columns headings for events: "
294  << "eventnum runnum timetaken\n"
295  << "TimeReport> Report columns headings for modules: "
296  << "eventnum runnum modulelabel modulename timetakeni\n"
297  << "TimeReport> JobTime=" << curr_job_time_ << " JobCPU=" << curr_job_cpu_ << "\n";
298  }
299  }
300 
302  double total_job_time = getTime() - curr_job_time_;
303 
304  double total_job_cpu = getCPU() - curr_job_cpu_;
305 
306  double min_event_time = *(std::min_element(min_events_time_.begin(),
307  min_events_time_.end()));
308  double max_event_time = *(std::max_element(max_events_time_.begin(),
309  max_events_time_.end()));
310 
311  auto total_loop_time = last_run_time_ - curr_job_time_;
312  auto total_loop_cpu = last_run_cpu_ - curr_job_cpu_;
313 
314  if(last_run_time_ == 0.0) {
315  total_loop_time = 0.0;
316  total_loop_cpu = 0.0;
317  }
318 
319  double sum_all_events_time = 0;
320  for(auto t : sum_events_time_) { sum_all_events_time += t; }
321 
322  double average_event_time = 0.0;
323  if(total_event_count_ != 0) {
324  average_event_time = sum_all_events_time / total_event_count_;
325  }
326 
327  double event_throughput = 0.0;
328  if(total_loop_time != 0.0) {
329  event_throughput = total_event_count_ / total_loop_time;
330  }
331 
332  LogImportant("TimeReport")
333  << "TimeReport> Time report complete in "
334  << total_job_time << " seconds"
335  << "\n"
336  << " Time Summary: \n"
337  << " - Min event: " << min_event_time << "\n"
338  << " - Max event: " << max_event_time << "\n"
339  << " - Avg event: " << average_event_time << "\n"
340  << " - Total loop: " <<total_loop_time <<"\n"
341  << " - Total job: " << total_job_time << "\n"
342  << " Event Throughput: "<< event_throughput <<" ev/s\n"
343  << " CPU Summary: \n"
344  << " - Total loop: " << total_loop_cpu << "\n"
345  << " - Total job: " << total_job_cpu << "\n";
346 
347  if(report_summary_) {
348  Service<JobReport> reportSvc;
349  std::map<std::string, std::string> reportData;
350 
351  reportData.insert(std::make_pair("MinEventTime", d2str(min_event_time)));
352  reportData.insert(std::make_pair("MaxEventTime", d2str(max_event_time)));
353  reportData.insert(std::make_pair("AvgEventTime", d2str(average_event_time)));
354  reportData.insert(std::make_pair("EventThroughput", d2str(event_throughput)));
355  reportData.insert(std::make_pair("TotalJobTime", d2str(total_job_time)));
356  reportData.insert(std::make_pair("TotalJobCPU", d2str(total_job_cpu)));
357  reportData.insert(std::make_pair("TotalLoopCPU", d2str(total_loop_cpu)));
358  reportData.insert(std::make_pair("NumberOfStreams",ui2str(nStreams_)));
359  reportData.insert(std::make_pair("NumberOfThreads",ui2str(nThreads_)));
360  reportSvc->reportPerformanceSummary("Timing", reportData);
361  }
362  }
363 
364  void Timing::preEvent(StreamContext const& iStream) {
365  auto index = iStream.streamID().value();
367  }
368 
369  void Timing::postEvent(StreamContext const& iStream) {
370  auto index = iStream.streamID().value();
371 
372  double curr_event_time = getTime() - curr_events_time_[index];
373  sum_events_time_[index] +=curr_event_time;
374 
375  if(not summary_only_) {
376  auto const & eventID = iStream.eventID();
377  LogPrint("TimeEvent")
378  << "TimeEvent> "
379  << eventID.event() << " "
380  << eventID.run() << " "
381  << curr_event_time ;
382  }
383  if(curr_event_time > max_events_time_[index]) max_events_time_[index] = curr_event_time;
384  if(curr_event_time < min_events_time_[index]) min_events_time_[index] = curr_event_time;
386  }
387 
388  void Timing::postModuleEvent(StreamContext const& iStream, ModuleCallingContext const& iModule) {
389  auto const & eventID = iStream.eventID();
390  auto const & desc = *(iModule.moduleDescription());
391  double t = postCommon();
392  if ( not summary_only_) {
393  LogPrint("TimeModule") << "TimeModule> "
394  << eventID.event() << " "
395  << eventID.run() << " "
396  << desc.moduleLabel() << " "
397  << desc.moduleName() << " "
398  << t;
399  }
400  }
401 
403  pushStack();
404  }
405 
407  postCommon();
408  }
409 
411  pushStack();
412  }
413 
415  postCommon();
416  }
417 
419  pushStack();
420  }
421 
423  postCommon();
424  }
425 
426  void Timing::preOpenFile(std::string const& lfn, bool b) {
427  pushStack();
428  }
429 
430  void Timing::postOpenFile(std::string const& lfn, bool b) {
431  postCommon();
432  }
433 
434  void
436  pushStack();
437  }
438 
439  void
441  postCommon();
442  }
443 
444  void
446  pushStack();
447  }
448 
449  void
451  postCommon();
452  }
453 
454  void
456  pushStack();
457  }
458 
459  void
461  postCommon();
462  }
463 
464  double
466  double t = popStack();
467  if(t > threshold_) {
468  LogError("ExcessiveTime")
469  << "ExcessiveTime: Module used " << t
470  << " seconds of time which exceeds the error threshold configured in the Timing Service of "
471  << threshold_ << " seconds.";
472  }
473  return t;
474  }
475  }
476 }
477 
479 
void watchPostModuleGlobalEndLumi(PostModuleGlobalEndLumi::slot_type const &iSlot)
void watchPostModuleConstruction(PostModuleConstruction::slot_type const &iSlot)
std::vector< double > sum_events_time_
Definition: Timing.cc:93
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:83
#define DEFINE_FWK_SERVICE_MAKER(concrete, maker)
Definition: ServiceMaker.h:117
std::vector< double > max_events_time_
Definition: Timing.cc:91
ParameterDescriptionBase * addUntracked(U const &iLabel, T const &value)
void watchPostEndJob(PostEndJob::slot_type const &iSlot)
std::vector< double > curr_events_time_
Definition: Timing.cc:84
void watchPreModuleEvent(PreModuleEvent::slot_type const &iSlot)
void watchPreModuleConstruction(PreModuleConstruction::slot_type const &iSlot)
void watchPostEvent(PostEvent::slot_type const &iSlot)
virtual double getTotalCPU() const override
Definition: Timing.cc:269
void preModule(ModuleDescription const &md)
Definition: Timing.cc:435
void watchPreSourceConstruction(PreSourceConstruction::slot_type const &iSlot)
static double getCPU()
Definition: Timing.cc:124
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:369
void preModuleStream(StreamContext const &, ModuleCallingContext const &)
Definition: Timing.cc:455
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:480
void watchPreModuleGlobalEndRun(PreModuleGlobalEndRun::slot_type const &iSlot)
unsigned int nThreads_
Definition: Timing.cc:96
void preOpenFile(std::string const &, bool)
Definition: Timing.cc:426
unsigned int nStreams_
Definition: Timing.cc:95
void preModuleGlobal(GlobalContext const &, ModuleCallingContext const &)
Definition: Timing.cc:445
void postModule(ModuleDescription const &md)
Definition: Timing.cc:440
static void pushStack()
Definition: Timing.cc:162
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:460
void watchPostSourceRun(PostSourceRun::slot_type const &iSlot)
Timing(ParameterSet const &, ActivityRegistry &)
Definition: Timing.cc:167
void watchPreSourceLumi(PreSourceLumi::slot_type const &iSlot)
ModuleDescription const * moduleDescription() const
void postModuleEvent(StreamContext const &, ModuleCallingContext const &)
Definition: Timing.cc:388
std::atomic< double > last_run_time_
Definition: Timing.cc:82
void watchPreModuleEndJob(PreModuleEndJob::slot_type const &iSlot)
static void fillDescriptions(edm::ConfigurationDescriptions &descriptions)
Definition: Timing.cc:273
void watchPreSourceRun(PreSourceRun::slot_type const &iSlot)
void preSourceLumi()
Definition: Timing.cc:410
void watchPreModuleBeginJob(PreModuleBeginJob::slot_type const &iSlot)
void postSourceRun()
Definition: Timing.cc:422
void watchPreModuleGlobalBeginLumi(PreModuleGlobalBeginLumi::slot_type const &iSlot)
void watchPostModuleStreamEndRun(PostModuleStreamEndRun::slot_type const &iSlot)
StreamID const & streamID() const
Definition: StreamContext.h:57
virtual void addToCPUTime(StreamID id, double iTime) override
Definition: Timing.cc:264
static std::string ui2str(unsigned int i)
Definition: Timing.cc:110
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:94
void watchPreModuleStreamEndLumi(PreModuleStreamEndLumi::slot_type const &iSlot)
void watchPreModuleStreamBeginRun(PreModuleStreamBeginRun::slot_type const &iSlot)
static std::vector< double > & moduleTimeStack()
Definition: Timing.cc:146
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:465
PostGlobalEndRun postGlobalEndRunSignal_
void postSourceLumi()
Definition: Timing.cc:414
void postModuleGlobal(GlobalContext const &, ModuleCallingContext const &)
Definition: Timing.cc:450
HLT enums.
void watchPreModuleStreamEndRun(PreModuleStreamEndRun::slot_type const &iSlot)
void postOpenFile(std::string const &, bool)
Definition: Timing.cc:430
static double getTime()
Definition: Timing.cc:117
void watchPostModuleBeginJob(PostModuleBeginJob::slot_type const &iSlot)
void postSourceEvent(StreamID)
Definition: Timing.cc:406
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)
static double popStack()
Definition: Timing.cc:152
void preSourceEvent(StreamID)
Definition: Timing.cc:402
void watchPostModuleEndJob(PostModuleEndJob::slot_type const &iSlot)
void connect(U iFunc)
Definition: Signal.h:63
void preEvent(StreamContext const &)
Definition: Timing.cc:364
void watchPreModuleGlobalEndLumi(PreModuleGlobalEndLumi::slot_type const &iSlot)
std::vector< double > min_events_time_
Definition: Timing.cc:92
void watchPostBeginJob(PostBeginJob::slot_type const &iSlot)
convenience function for attaching to signal