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 
25 
26 #include <iostream>
27 #include <sstream>
28 #include <sys/resource.h>
29 #include <sys/time.h>
30 
31 namespace edm {
32  namespace service {
33 
34  static std::string d2str(double d) {
35  std::stringstream t;
36  t << d;
37  return t.str();
38  }
39 
40  static double getTime() {
41  struct timeval t;
42  if(gettimeofday(&t, 0) < 0)
43  throw cms::Exception("SysCallFailed", "Failed call to gettimeofday");
44  return static_cast<double>(t.tv_sec) + (static_cast<double>(t.tv_usec) * 1E-6);
45  }
46 
47  static double getCPU() {
48  struct rusage usage;
49  getrusage(RUSAGE_SELF, &usage);
50 
51  double totalCPUTime = 0.0;
52  // User code
53  totalCPUTime = (double)usage.ru_utime.tv_sec + (double(usage.ru_utime.tv_usec) * 1E-6);
54  // System functions
55  totalCPUTime += (double)usage.ru_stime.tv_sec + (double(usage.ru_stime.tv_usec) * 1E-6);
56  return totalCPUTime;
57  }
58 
59  //NOTE: We use a per thread stack for module times since unscheduled
60  // exectuion or tbb task spawning can cause a module to run on the
61  // same thread as an already running module
62  static
63  std::vector<double>& moduleTimeStack() {
64  static thread_local std::vector<double> s_stack;
65  return s_stack;
66  }
67 
68  Timing::Timing(ParameterSet const& iPS, ActivityRegistry& iRegistry) :
69  curr_job_time_(0.),
70  curr_job_cpu_(0.),
71  curr_events_time_(),
72  curr_events_cpu_(),
73  total_events_cpu_(),
74  summary_only_(iPS.getUntrackedParameter<bool>("summaryOnly")),
75  report_summary_(iPS.getUntrackedParameter<bool>("useJobReport")),
76  max_events_time_(),
77  max_events_cpu_(),
78  min_events_time_(),
79  min_events_cpu_(),
80  total_event_count_(0) {
81  iRegistry.watchPostBeginJob(this, &Timing::postBeginJob);
82  iRegistry.watchPostEndJob(this, &Timing::postEndJob);
83 
84  iRegistry.watchPreEvent(this, &Timing::preEvent);
85  iRegistry.watchPostEvent(this, &Timing::postEvent);
86 
87  if(not summary_only_) {
88  iRegistry.watchPreModuleEvent(this, &Timing::preModule);
89  iRegistry.watchPostModuleEvent(this, &Timing::postModule);
90  }
91 
92  iRegistry.preallocateSignal_.connect([this](service::SystemBounds const& iBounds){
93  auto nStreams = iBounds.maxNumberOfStreams();
94  curr_events_time_.resize(nStreams,0.);
95  curr_events_cpu_.resize(nStreams,0.);
96  total_events_cpu_.resize(nStreams,0.);
97  max_events_time_.resize(nStreams,0.);
98  max_events_cpu_.resize(nStreams,0.);
99  min_events_time_.resize(nStreams,1.E6);
100  min_events_cpu_.resize(nStreams,1.E6);
101  });
102  }
103 
105  }
106 
109  desc.addUntracked<bool>("summaryOnly", false)->setComment(
110  "If 'true' do not report timing for each event");
111  desc.addUntracked<bool>("useJobReport", true)->setComment(
112  "If 'true' write summary information to JobReport");
113  descriptions.add("Timing", desc);
114  descriptions.setComment(
115  "This service reports the time it takes to run each module in a job.");
116  }
117 
120  curr_job_cpu_ = getCPU();
121 
122  if(not summary_only_) {
123  LogImportant("TimeReport")
124  << "TimeReport> Report activated" << "\n"
125  << "TimeReport> Report columns headings for events: "
126  << "eventnum runnum timetaken\n"
127  << "TimeReport> Report columns headings for modules: "
128  << "eventnum runnum modulelabel modulename timetakeni\n"
129  << "TimeReport> JobTime=" << curr_job_time_ << " JobCPU=" << curr_job_cpu_ << "\n";
130  }
131  }
132 
134  double total_job_time = getTime() - curr_job_time_;
135  double average_event_time = total_job_time / total_event_count_;
136 
137  double total_job_cpu = getCPU() - curr_job_cpu_;
138  double total_event_cpu = 0.;
139  for(auto t : total_events_cpu_) {
140  total_event_cpu +=t;
141  }
142  double average_event_cpu = total_event_cpu / total_event_count_;
143 
144  double min_event_time = *(std::min_element(min_events_time_.begin(),
145  min_events_time_.end()));
146  double max_event_time = *(std::max_element(max_events_time_.begin(),
147  max_events_time_.end()));
148  double min_event_cpu = *(std::min_element(min_events_cpu_.begin(),
149  min_events_cpu_.end()));
150  double max_event_cpu = *(std::max_element(max_events_cpu_.begin(),
151  max_events_cpu_.end()));
152  LogImportant("TimeReport")
153  << "TimeReport> Time report complete in "
154  << total_job_time << " seconds"
155  << "\n"
156  << " Time Summary: \n"
157  << " - Min event: " << min_event_time << "\n"
158  << " - Max event: " << max_event_time << "\n"
159  << " - Avg event: " << average_event_time << "\n"
160  << " - Total job: " << total_job_time << "\n"
161  << " CPU Summary: \n"
162  << " - Min event: " << min_event_cpu << "\n"
163  << " - Max event: " << max_event_cpu << "\n"
164  << " - Avg event: " << average_event_cpu << "\n"
165  << " - Total job: " << total_job_cpu << "\n"
166  << " - Total event: " << total_event_cpu << "\n";
167 
168  if(report_summary_) {
169  Service<JobReport> reportSvc;
170  std::map<std::string, std::string> reportData;
171 
172  reportData.insert(std::make_pair("MinEventTime", d2str(min_event_time)));
173  reportData.insert(std::make_pair("MaxEventTime", d2str(max_event_time)));
174  reportData.insert(std::make_pair("AvgEventTime", d2str(average_event_time)));
175  reportData.insert(std::make_pair("TotalJobTime", d2str(total_job_time)));
176  reportData.insert(std::make_pair("MinEventCPU", d2str(min_event_cpu)));
177  reportData.insert(std::make_pair("MaxEventCPU", d2str(max_event_cpu)));
178  reportData.insert(std::make_pair("AvgEventCPU", d2str(average_event_cpu)));
179  reportData.insert(std::make_pair("TotalJobCPU", d2str(total_job_cpu)));
180  reportData.insert(std::make_pair("TotalEventCPU", d2str(total_event_cpu)));
181 
182  reportSvc->reportPerformanceSummary("Timing", reportData);
183  }
184  }
185 
186  void Timing::preEvent(StreamContext const& iStream) {
187  auto index = iStream.streamID().value();
190  }
191 
192  void Timing::postEvent(StreamContext const& iStream) {
193  auto index = iStream.streamID().value();
194  double curr_event_cpu = getCPU() - curr_events_cpu_[index];
195  total_events_cpu_[index] += curr_event_cpu;
196 
197  double curr_event_time = getTime() - curr_events_time_[index];
198 
199  if(not summary_only_) {
200  auto const & eventID = iStream.eventID();
201  LogPrint("TimeEvent")
202  << "TimeEvent> "
203  << eventID.event() << " "
204  << eventID.run() << " "
205  << curr_event_time << " "
206  << curr_event_cpu << " "
208  }
209  if(curr_event_time > max_events_time_[index]) max_events_time_[index] = curr_event_time;
210  if(curr_event_time < min_events_time_[index]) min_events_time_[index] = curr_event_time;
211  if(curr_event_cpu > max_events_cpu_[index]) max_events_cpu_[index] = curr_event_cpu;
212  if(curr_event_cpu < min_events_cpu_[index]) min_events_cpu_[index] = curr_event_cpu;
214  }
215 
217  auto & modStack = moduleTimeStack();
218  modStack.push_back(getTime());
219  }
220 
221  void Timing::postModule(StreamContext const& iStream, ModuleCallingContext const& iModule) {
222  //LogInfo("TimeModule")
223  auto& modStack = moduleTimeStack();
224  assert(modStack.size() > 0);
225  double curr_module_time = modStack.back();
226  modStack.pop_back();
227  double t = getTime() - curr_module_time;
228  //move waiting module start times forward to account
229  // for the fact that they were paused while this module ran
230  for(auto& waitingModuleStartTime : modStack) {
231  waitingModuleStartTime +=t;
232  }
233  auto const & eventID = iStream.eventID();
234  auto const & desc = *(iModule.moduleDescription());
235 
236  LogPrint("TimeModule") << "TimeModule> "
237  << eventID.event() << " "
238  << eventID.run() << " "
239  << desc.moduleLabel() << " "
240  << desc.moduleName() << " "
241  << t;
242  }
243  }
244 }
245 
void watchPreEvent(PreEvent::slot_type const &iSlot)
double curr_job_time_
Definition: Timing.h:42
std::vector< double > max_events_time_
Definition: Timing.h:53
ParameterDescriptionBase * addUntracked(U const &iLabel, T const &value)
bool report_summary_
Definition: Timing.h:48
void watchPostEndJob(PostEndJob::slot_type const &iSlot)
std::vector< double > curr_events_time_
Definition: Timing.h:44
void watchPreModuleEvent(PreModuleEvent::slot_type const &iSlot)
void watchPostEvent(PostEvent::slot_type const &iSlot)
static double getCPU()
Definition: Timing.cc:47
void watchPostModuleEvent(PostModuleEvent::slot_type const &iSlot)
void postEvent(StreamContext const &)
Definition: Timing.cc:192
double curr_job_cpu_
Definition: Timing.h:43
std::vector< double > curr_events_cpu_
Definition: Timing.h:45
Preallocate preallocateSignal_
signal is emitted before beginJob
unsigned int maxNumberOfStreams() const
Definition: SystemBounds.h:43
std::vector< double > total_events_cpu_
Definition: Timing.h:46
Timing(ParameterSet const &, ActivityRegistry &)
Definition: Timing.cc:68
ModuleDescription const * moduleDescription() const
static void fillDescriptions(edm::ConfigurationDescriptions &descriptions)
Definition: Timing.cc:107
StreamID const & streamID() const
Definition: StreamContext.h:57
void setComment(std::string const &value)
unsigned int value() const
Definition: StreamID.h:46
std::atomic< unsigned long > total_event_count_
Definition: Timing.h:57
static std::vector< double > & moduleTimeStack()
Definition: Timing.cc:63
static std::string d2str(double d)
Definition: Memory.cc:62
void add(std::string const &label, ParameterSetDescription const &psetDescription)
std::vector< double > max_events_cpu_
Definition: Timing.h:54
std::vector< double > min_events_cpu_
Definition: Timing.h:56
static double getTime()
EventID const & eventID() const
Definition: StreamContext.h:59
void postModule(StreamContext const &, ModuleCallingContext const &)
Definition: Timing.cc:221
void connect(U iFunc)
Definition: Signal.h:63
void preEvent(StreamContext const &)
Definition: Timing.cc:186
void preModule(StreamContext const &, ModuleCallingContext const &)
Definition: Timing.cc:216
std::vector< double > min_events_time_
Definition: Timing.h:55
void watchPostBeginJob(PostBeginJob::slot_type const &iSlot)
convenience function for attaching to signal