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