CMS 3D CMS Logo

 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
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 
54  void preModule(StreamContext const&, ModuleCallingContext const&);
55  void postModule(StreamContext const&, ModuleCallingContext const&);
56 
57  double curr_job_time_; // seconds
58  double curr_job_cpu_; // seconds
59  //use last run time for determining end of processing
60  std::atomic<double> last_run_time_;
61  std::atomic<double> last_run_cpu_;
62  std::vector<double> curr_events_time_; // seconds
65 
66  //
67  // Min Max and total event times for each Stream.
68  // Used for summary at end of job
69  std::vector<double> max_events_time_; // seconds
70  std::vector<double> min_events_time_; // seconds
71  std::vector<double> sum_events_time_;
72  std::atomic<unsigned long> total_event_count_;
73  unsigned int nStreams_;
74  unsigned int nThreads_;
75  };
76  }
77 }
78 
79 namespace edm {
80  namespace service {
81 
82  static std::string d2str(double d) {
83  std::stringstream t;
84  t << d;
85  return t.str();
86  }
87 
88  static std::string ui2str(unsigned int i) {
89  std::stringstream t;
90  t << i;
91  return t.str();
92  }
93 
94 
95  static double getTime() {
96  struct timeval t;
97  if(gettimeofday(&t, 0) < 0)
98  throw cms::Exception("SysCallFailed", "Failed call to gettimeofday");
99  return static_cast<double>(t.tv_sec) + (static_cast<double>(t.tv_usec) * 1E-6);
100  }
101 
102  static double getCPU() {
103  struct rusage usage;
104  getrusage(RUSAGE_SELF, &usage);
105 
106  double totalCPUTime = 0.0;
107  // User code
108  totalCPUTime = (double)usage.ru_utime.tv_sec + (double(usage.ru_utime.tv_usec) * 1E-6);
109  // System functions
110  totalCPUTime += (double)usage.ru_stime.tv_sec + (double(usage.ru_stime.tv_usec) * 1E-6);
111 
112  // Additionally, add in CPU usage from our child processes.
113  getrusage(RUSAGE_CHILDREN, &usage);
114  totalCPUTime += (double)usage.ru_utime.tv_sec + (double(usage.ru_utime.tv_usec) * 1E-6);
115  totalCPUTime += (double)usage.ru_stime.tv_sec + (double(usage.ru_stime.tv_usec) * 1E-6);
116 
117  return totalCPUTime;
118  }
119 
120  //NOTE: We use a per thread stack for module times since unscheduled
121  // exectuion or tbb task spawning can cause a module to run on the
122  // same thread as an already running module
123  static
124  std::vector<double>& moduleTimeStack() {
125  static thread_local std::vector<double> s_stack;
126  return s_stack;
127  }
128 
129  Timing::Timing(ParameterSet const& iPS, ActivityRegistry& iRegistry) :
130  curr_job_time_(0.),
131  curr_job_cpu_(0.),
132  last_run_time_(0.0),
133  last_run_cpu_(0.0),
134  curr_events_time_(),
135  summary_only_(iPS.getUntrackedParameter<bool>("summaryOnly")),
136  report_summary_(iPS.getUntrackedParameter<bool>("useJobReport")),
137  max_events_time_(),
138  min_events_time_(),
139  total_event_count_(0) {
140  iRegistry.watchPostBeginJob(this, &Timing::postBeginJob);
141  iRegistry.watchPostEndJob(this, &Timing::postEndJob);
142 
143  iRegistry.watchPreEvent(this, &Timing::preEvent);
144  iRegistry.watchPostEvent(this, &Timing::postEvent);
145 
146  if(not summary_only_) {
147  iRegistry.watchPreModuleEvent(this, &Timing::preModule);
148  iRegistry.watchPostModuleEvent(this, &Timing::postModule);
149  }
150 
151  iRegistry.preallocateSignal_.connect([this](service::SystemBounds const& iBounds){
152  nStreams_ = iBounds.maxNumberOfStreams();
153  nThreads_ = iBounds.maxNumberOfThreads();
154  curr_events_time_.resize(nStreams_,0.);
155  sum_events_time_.resize(nStreams_,0.);
156  max_events_time_.resize(nStreams_,0.);
157  min_events_time_.resize(nStreams_,1.E6);
158 
159  });
160 
161  iRegistry.postGlobalEndRunSignal_.connect([this](edm::GlobalContext const&) {
163  last_run_cpu_ = getCPU();
164  });
165  }
166 
168  }
169 
170  void Timing::addToCPUTime(StreamID id, double iTime) {
171  //For accounting purposes we effectively can say we started earlier
172  curr_job_cpu_ -= iTime;
173  }
174 
175  double Timing::getTotalCPU() const {
176  return getCPU();
177  }
178 
181  desc.addUntracked<bool>("summaryOnly", false)->setComment(
182  "If 'true' do not report timing for each event");
183  desc.addUntracked<bool>("useJobReport", true)->setComment(
184  "If 'true' write summary information to JobReport");
185  descriptions.add("Timing", desc);
186  descriptions.setComment(
187  "This service reports the time it takes to run each module in a job.");
188  }
189 
192  curr_job_cpu_ = getCPU();
193 
194  if(not summary_only_) {
195  LogImportant("TimeReport")
196  << "TimeReport> Report activated" << "\n"
197  << "TimeReport> Report columns headings for events: "
198  << "eventnum runnum timetaken\n"
199  << "TimeReport> Report columns headings for modules: "
200  << "eventnum runnum modulelabel modulename timetakeni\n"
201  << "TimeReport> JobTime=" << curr_job_time_ << " JobCPU=" << curr_job_cpu_ << "\n";
202  }
203  }
204 
206  double total_job_time = getTime() - curr_job_time_;
207 
208  double total_job_cpu = getCPU() - curr_job_cpu_;
209 
210  double min_event_time = *(std::min_element(min_events_time_.begin(),
211  min_events_time_.end()));
212  double max_event_time = *(std::max_element(max_events_time_.begin(),
213  max_events_time_.end()));
214 
215  auto total_loop_time = last_run_time_ - curr_job_time_;
216  auto total_loop_cpu = last_run_cpu_ - curr_job_cpu_;
217 
218  if(last_run_time_ == 0.0) {
219  total_loop_time = 0.0;
220  total_loop_cpu = 0.0;
221  }
222 
223  double sum_all_events_time = 0;
224  for(auto t : sum_events_time_) { sum_all_events_time += t; }
225 
226  double average_event_time = 0.0;
227  if(total_event_count_ != 0) {
228  average_event_time = sum_all_events_time / total_event_count_;
229  }
230 
231  double event_throughput = 0.0;
232  if(total_loop_time != 0.0) {
233  event_throughput = total_event_count_ / total_loop_time;
234  }
235 
236  LogImportant("TimeReport")
237  << "TimeReport> Time report complete in "
238  << total_job_time << " seconds"
239  << "\n"
240  << " Time Summary: \n"
241  << " - Min event: " << min_event_time << "\n"
242  << " - Max event: " << max_event_time << "\n"
243  << " - Avg event: " << average_event_time << "\n"
244  << " - Total loop: " <<total_loop_time <<"\n"
245  << " - Total job: " << total_job_time << "\n"
246  << " Event Throughput: "<< event_throughput <<" ev/s\n"
247  << " CPU Summary: \n"
248  << " - Total loop: " << total_loop_cpu << "\n"
249  << " - Total job: " << total_job_cpu << "\n";
250 
251  if(report_summary_) {
252  Service<JobReport> reportSvc;
253  std::map<std::string, std::string> reportData;
254 
255  reportData.insert(std::make_pair("MinEventTime", d2str(min_event_time)));
256  reportData.insert(std::make_pair("MaxEventTime", d2str(max_event_time)));
257  reportData.insert(std::make_pair("AvgEventTime", d2str(average_event_time)));
258  reportData.insert(std::make_pair("EventThroughput", d2str(event_throughput)));
259  reportData.insert(std::make_pair("TotalJobTime", d2str(total_job_time)));
260  reportData.insert(std::make_pair("TotalJobCPU", d2str(total_job_cpu)));
261  reportData.insert(std::make_pair("TotalLoopCPU", d2str(total_loop_cpu)));
262  reportData.insert(std::make_pair("NumberOfStreams",ui2str(nStreams_)));
263  reportData.insert(std::make_pair("NumberOfThreads",ui2str(nThreads_)));
264  reportSvc->reportPerformanceSummary("Timing", reportData);
265  }
266  }
267 
268  void Timing::preEvent(StreamContext const& iStream) {
269  auto index = iStream.streamID().value();
271  }
272 
273  void Timing::postEvent(StreamContext const& iStream) {
274  auto index = iStream.streamID().value();
275 
276  double curr_event_time = getTime() - curr_events_time_[index];
277  sum_events_time_[index] +=curr_event_time;
278 
279  if(not summary_only_) {
280  auto const & eventID = iStream.eventID();
281  LogPrint("TimeEvent")
282  << "TimeEvent> "
283  << eventID.event() << " "
284  << eventID.run() << " "
285  << curr_event_time ;
286  }
287  if(curr_event_time > max_events_time_[index]) max_events_time_[index] = curr_event_time;
288  if(curr_event_time < min_events_time_[index]) min_events_time_[index] = curr_event_time;
290  }
291 
293  auto & modStack = moduleTimeStack();
294  modStack.push_back(getTime());
295  }
296 
297  void Timing::postModule(StreamContext const& iStream, ModuleCallingContext const& iModule) {
298  //LogInfo("TimeModule")
299  auto& modStack = moduleTimeStack();
300  assert(modStack.size() > 0);
301  double curr_module_time = modStack.back();
302  modStack.pop_back();
303  double t = getTime() - curr_module_time;
304  //move waiting module start times forward to account
305  // for the fact that they were paused while this module ran
306  for(auto& waitingModuleStartTime : modStack) {
307  waitingModuleStartTime +=t;
308  }
309  auto const & eventID = iStream.eventID();
310  auto const & desc = *(iModule.moduleDescription());
311 
312  LogPrint("TimeModule") << "TimeModule> "
313  << eventID.event() << " "
314  << eventID.run() << " "
315  << desc.moduleLabel() << " "
316  << desc.moduleName() << " "
317  << t;
318  }
319  }
320 }
321 
323 
std::vector< double > sum_events_time_
Definition: Timing.cc:71
unsigned int maxNumberOfThreads() const
Definition: SystemBounds.h:46
void watchPreEvent(PreEvent::slot_type const &iSlot)
int i
Definition: DBlmapReader.cc:9
double curr_job_time_
Definition: Timing.cc:57
std::atomic< double > last_run_cpu_
Definition: Timing.cc:61
#define DEFINE_FWK_SERVICE_MAKER(concrete, maker)
Definition: ServiceMaker.h:117
std::vector< double > max_events_time_
Definition: Timing.cc:69
ParameterDescriptionBase * addUntracked(U const &iLabel, T const &value)
void watchPostEndJob(PostEndJob::slot_type const &iSlot)
std::vector< double > curr_events_time_
Definition: Timing.cc:62
void watchPreModuleEvent(PreModuleEvent::slot_type const &iSlot)
void watchPostEvent(PostEvent::slot_type const &iSlot)
assert(m_qm.get())
static double getCPU()
Definition: Timing.cc:102
void watchPostModuleEvent(PostModuleEvent::slot_type const &iSlot)
void postEvent(StreamContext const &)
Definition: Timing.cc:273
double curr_job_cpu_
Definition: Timing.cc:58
edm::serviceregistry::AllArgsMaker< edm::TimingServiceBase, Timing > TimingMaker
Definition: Timing.cc:324
unsigned int nThreads_
Definition: Timing.cc:74
unsigned int nStreams_
Definition: Timing.cc:73
Preallocate preallocateSignal_
signal is emitted before beginJob
unsigned int maxNumberOfStreams() const
Definition: SystemBounds.h:43
tuple d
Definition: ztail.py:151
Timing(ParameterSet const &, ActivityRegistry &)
Definition: Timing.cc:129
ModuleDescription const * moduleDescription() const
std::atomic< double > last_run_time_
Definition: Timing.cc:60
static void fillDescriptions(edm::ConfigurationDescriptions &descriptions)
Definition: Timing.cc:179
virtual double getTotalCPU() const override
Definition: Timing.cc:175
StreamID const & streamID() const
Definition: StreamContext.h:57
virtual void addToCPUTime(StreamID id, double iTime) override
Definition: Timing.cc:170
static std::string ui2str(unsigned int i)
Definition: Timing.cc:88
void setComment(std::string const &value)
unsigned int value() const
Definition: StreamID.h:46
std::atomic< unsigned long > total_event_count_
Definition: Timing.cc:72
static std::vector< double > & moduleTimeStack()
Definition: Timing.cc:124
static std::string d2str(double d)
void add(std::string const &label, ParameterSetDescription const &psetDescription)
PostGlobalEndRun postGlobalEndRunSignal_
static double getTime()
Definition: Timing.cc:95
EventID const & eventID() const
Definition: StreamContext.h:59
void postModule(StreamContext const &, ModuleCallingContext const &)
Definition: Timing.cc:297
void connect(U iFunc)
Definition: Signal.h:63
void preEvent(StreamContext const &)
Definition: Timing.cc:268
void preModule(StreamContext const &, ModuleCallingContext const &)
Definition: Timing.cc:292
std::vector< double > min_events_time_
Definition: Timing.cc:70
void watchPostBeginJob(PostBeginJob::slot_type const &iSlot)
convenience function for attaching to signal