IntelProfilerAuditor.cpp
Go to the documentation of this file.
1 // ## Includes.
2 // * Standard libraries.
3 #include <algorithm>
4 #include <vector>
5 #include <stack>
6 #include <string>
7 #include <utility>
8 #include <memory>
9 #include <iomanip>
10 #include <sstream>
11 
12 // * Gaudi libraries.
13 #include "GaudiKernel/Auditor.h"
16 #include "GaudiKernel/MsgStream.h"
19 
20 // * Intel User API
21 #ifdef __GNUC__
22 #pragma GCC diagnostic ignored "-Wunused-function"
23 #endif
24 #include "ittnotify.h"
25 
27 
28 // Gaudi profiling auditor. The auditor use Intel API for control profiling
29 // flow. We need to run profiling throw Intel Amplifier amplxe-cl command
30 // line tool.
31 class IntelProfilerAuditor: public Auditor, virtual public IIncidentListener {
32 public:
33  // ## Public functions.
34  IntelProfilerAuditor(const std::string& name, ISvcLocator* pSvcLocator);
36  // Overridden functions.
37  void handle(const Incident& incident);
38  using Auditor::before; // avoid hiding base-class methods
39  void before(StandardEventType type, INamedInterface* i);
40  using Auditor::after; // avoid hiding base-class methods
41  void after(StandardEventType type, INamedInterface* i, const StatusCode& sc);
42 // ## Private attributes.
43 private:
44  // Stack for store current component(algorithm) chain with useful
45  // information for the auditor.
46  struct stack_entity {
47  stack_entity(const std::string& name_, bool status_,
48  const __itt_event event_ = 0, const __itt_event parent_event_ = 0):
49  name(name_),
50  status(status_),
51  event(event_),
52  parent_event(parent_event_){}
53  // Name of the component.
55  // Running status: on/off.
56  bool status;
57  // Task type holder.
58  __itt_event event;
59  // Parent task type.
60  __itt_event parent_event;
61  };
62 private:
63  // From what event to start profiling. Default = 1.
65  // After what event we stop profiling. If 0 than we also profile finalization
66  // stage. Default = 0.
68  // Names of excluded algorithms.
70  // Names of included algorithms.
72  // Algorithm name, for which intel amplifier event type will be created.
74  // The String delimiter between sequences/algorithms names in
75  // "Task Type" grouping at Amplifier.
77  // Enable frames (needed for detecting slow events).
79  // Frames rate. The recommended maximum rate for calling the Frame API is
80  // 1000 frames (events) per second. A higher rate may result in large product
81  // memory consumption and slow finalization.
82  // You need update "slow-frames-threshold" and "fast-frames-threshold"
83  // parameters of amplxe-cl tool to separate slow, medium and fast events.
85 private:
86  // Events counter.
87  int m_nEvents;
88  // Domain for event loop.
89  __itt_domain* domain;
90  // True if profiler is started.
92  // Current stack of sequences/algorithms.
94  // Mapping of task type name to Amplifier event .
96 private:
97  // ## Private functions.
98  void start_profiling_component(const std::string& name);
99  void skip_profiling_component(const std::string& name);
100 
101  void start();
102  void pause();
103  void resume();
104  void stop();
105 
106  bool hasIncludes() const;
107  bool isIncluded(const std::string& name) const;
108  bool isExcluded(const std::string& name) const;
109  bool isRunning() const;
110 
111  int stackLevel() const;
112  std::string stackIndent(bool newLevel = false) const;
113  std::string taskTypeName(const std::string& component_name) const;
114 };
115 // ## Implementation.
116 // Constructor
118  ISvcLocator* pSvcLocator) : Auditor(name, pSvcLocator)
119  ,m_nEvents(0), m_isStarted(false) {
120  // ## Properties
121  declareProperty("IncludeAlgorithms", m_included,
122  "Names of included algorithms."
123  );
124  declareProperty("ExcludeAlgorithms", m_excluded,
125  "Names of excluded algorithms."
126  );
127  declareProperty("StartFromEventN", m_nStartFromEvent = 1,
128  "After what event we stop profiling. "
129  "If 0 than we also profile finalization stage."
130  );
131  declareProperty("StopAtEventN", m_nStopAtEvent = 0,
132  "After what event we stop profiling. "
133  "If 0 than we also profile finalization stage. Default = 0."
134  );
135  declareProperty("ComponentsForTaskTypes", m_algs_for_tasktypes,
136  "Algorithm name, for which intel amplifier task type will be created."
137  "By default all algorithms have a corresponding task type.");
138  declareProperty("TaskTypeNameDelimeter", m_alg_delim = " ",
139  "The String delimiter between sequences/algorithms names in "
140  "\"Task Type\" grouping at Amplifier. Default=\" \"."
141  );
142  declareProperty("EnableFrames", m_enable_frames = false,
143  "Enable frames (needed for detecting slow events). Default=false."
144  );
145  declareProperty("FramesRate", m_frames_rate = 100,
146  "Frames rate. The recommended maximum rate for calling the Frame API is "
147  "1000 frames (events) per second. A higher rate may result in large product"
148  " memory consumption and slow finalization. "
149  "You need update \"slow-frames-threshold\" and \"fast-frames-threshold\" "
150  "parameters of amplxe-cl tool to separate slow, medium and fast events. "
151  "For use frames you need to switch on \"EnableFrames\". "
152  "Default=100"
153  );
154 }
155 
157  m_isStarted = true;
158  __itt_resume();
159 }
160 
162  if (!m_isStarted) return;
164  __itt_event taskId = 0;
165  TaskTypes::const_iterator iter = m_tasktypes.find(typeName);
166  if( iter != m_tasktypes.end()) {
167  taskId = iter->second;
168  }
169 
170  if(!taskId && m_algs_for_tasktypes.empty()) {
171  // Create event
172  taskId = __itt_event_create(typeName.c_str(), typeName.size());
173  m_tasktypes.insert(TaskTypes::value_type(typeName, taskId));
174  }
175 
176  stack_entity state = stack_entity(name, true, taskId);
177  stack_entity* parent = !m_stack.empty()?&m_stack.back():NULL;
178 
179  if (parent != NULL) {
180  if (parent->event) {
181  state.parent_event = parent->event;
182  } else {
183  state.parent_event = parent->parent_event;
184  }
185  }
186 
187  if (taskId && state.parent_event) {
188  debug() << stackIndent() << "Pause event " <<
189  state.parent_event << endmsg;
190  __itt_event_end(state.parent_event);
191  }
192  m_stack.push_back(state);
193 
194  debug() << stackIndent() << "Start profiling component "
195  << typeName << endmsg;
196 
197  if (taskId) {
198  // Start event
199  debug() << stackIndent() << "Start event type "
200  << state.event << " for " << typeName << endmsg;
201  __itt_event_start(state.event);
202  }
203 
204  __itt_resume();
205 }
206 
208  if (!m_isStarted) return;
209  debug() << stackIndent() << "Resume" << endmsg;
210  __itt_resume();
211 }
212 
214  if (!m_isStarted) return;
215  debug() << stackIndent() << "Pause" << endmsg;
216  __itt_pause();
217 }
218 
220  if (!m_isStarted) return;
221  m_stack.push_back(stack_entity(name, false));
222  debug() << stackIndent() << "Skip component "
223  << name << endmsg;
224 }
225 
227  if (!m_isStarted) return;
228  m_isStarted = false;
229  __itt_pause();
230 }
231 
233  return !m_included.empty();
234 }
235 
237  return std::find(m_included.begin(), m_included.end(), name) !=
238  m_included.end();
239 }
240 
242  return std::find(m_excluded.begin(), m_excluded.end(), name) !=
243  m_excluded.end();
244 }
245 
247  return !m_stack.empty() && m_stack.back().status;
248 }
249 
251  return m_stack.size();
252 }
253 
255  std::stringstream indent(std::stringstream::out);
256  indent << std::setw(stackLevel()*2+(newLevel?2:0)) << " ";
257  return indent.str();
258 }
259 
261 IntelProfilerAuditor::taskTypeName(const std::string& component_name) const {
262  std::string result;
263  std::string delim = "";
264  for (const auto& value : m_stack) {
265  result += delim+value.name;
266  delim = m_alg_delim;
267  }
268  return result+m_alg_delim+component_name;
269 }
270 
272  info() << "Initialised" << endmsg;
273 
274  IIncidentSvc * inSvc = NULL;
275  const StatusCode sc = serviceLocator()->service("IncidentSvc", inSvc);
276  if (sc.isFailure())
277  return sc;
278  // Useful to start profiling only after some event, we don't need profile
279  // initialization stage. For that we need to count events with BeginEvent
280  // listener.
281  inSvc->addListener(this, IncidentType::BeginEvent);
282  // If the end event number don't setup we finish profiling at the end
283  // of loop. We don't need profiling finalization stage.
284  inSvc->addListener(this, IncidentType::EndProcessing);
285 
286  std::string str_excluded, str_included, str_eventtypes;
287  for (const auto& name : m_excluded) {
288  str_excluded += " " + name;
289  }
290  for (const auto& name : m_included) {
291  str_included += " " + name;
292  }
293  for (const auto& name : m_algs_for_tasktypes) {
294  str_eventtypes += " " + name;
295  }
296 
297  if (!m_included.empty()) {
298  info() << "Included algorithms (" << m_included.size()
299  << "): " << str_included << endmsg;
300  }
301 
302  if (!m_excluded.empty()){
303  info() << "Excluded algorithms (" << m_excluded.size()
304  << "): " << str_excluded << endmsg;
305  }
306 
307  if (!m_algs_for_tasktypes.empty()){
308  info() << "Event types (" << m_algs_for_tasktypes.size()
309  << "): " << str_eventtypes << endmsg;
310  }
311 
312  // Create a profiler domain for detection of slow events.
313  domain = __itt_domain_create("Event loop");
314  domain->flags = m_enable_frames;
315 
316  return StatusCode::SUCCESS;
317 }
318 
319 
320 
321 void IntelProfilerAuditor::handle(const Incident& incident) {
322  if (IncidentType::BeginEvent != incident.type()) return;
323  // Increment the event counter
324  ++m_nEvents;
325 
326  if (m_nStartFromEvent == m_nEvents) {
327  info() << "Start profiling (event #" << m_nEvents << ")"
328  << endmsg;
329  start();
330  }
331 
332  if (m_nStopAtEvent == m_nEvents) {
333  info() << "Stop profiling (event #" << m_nEvents << ")"
334  << endmsg;
335  stop();
336  }
337 }
338 
340  // Skip unnecessary event types.
341  if (!((type == IAuditor::Execute) && m_isStarted)) return;
342 
343  // Name of the current component.
344  const std::string& name = i->name();
345  //debug() << "Before: " << name << " " << type << endmsg;
346 
347  if (isRunning()) {
348  if (isExcluded(name)) {
349  // If profiling is running and component is explicitly excluded
350  // then skip component.
352  }else{
353  // If profiling is running and component is'not explicitly excluded
354  // then start profiling for component (add to stack).
356  }
357  }else {
358  if (hasIncludes()) {
359  // If the profiling is not running and "includes" is explicitly defined ...
360  if (isIncluded(name)) {
361  // and the current component is in the include's list then start the
362  // component profiling.
364  } else{
365  // and the current component is not in the includes list then skip
366  // a profiling of the component.
368  }
369  }else {
370  // If "Includes" property isn't present and the component is ...
371  if (isExcluded(name)) {
372  // in the excludes list then skip a profiling
374  }else{
375  // not in the exclude list then start a profiling
377  }
378  }
379  }
380  if (m_nEvents % m_frames_rate == 0) {
381  __itt_frame_begin_v3(domain, NULL);
382  }
383 
384 }
385 
386 void IntelProfilerAuditor::after(StandardEventType type,
387  INamedInterface* i, const StatusCode&/* sc*/) {
388  // Skip unnecessary event types
389  if (!((type == IAuditor::Execute) && m_isStarted)) return;
390 
391  if ((m_nEvents+1) % m_frames_rate == 0) {
392  __itt_frame_end_v3(domain, NULL);
393  }
394 
395  // Name of the current component
396  const std::string& name = i->name();
397  stack_entity state = m_stack.back();
398  // Remove component from stack.
399  m_stack.pop_back();
400 
401 
402  if (state.event != 0) {
403  debug() << stackIndent(true) << "End event for "
404  << name << endmsg;
405  __itt_event_end(state.event);
406 
407  if (state.parent_event != 0) {
408  debug() << stackIndent() << "Resume event for "
409  << state.parent_event << endmsg;
410  __itt_event_start(state.parent_event);
411  }
412  }
413 
414  if (m_stack.empty()) {
415  // Pause if there are no parent components (top algorithm).
416  pause();
417  } else if (state.status) {
418  // If the profiling is running and we have parent component that is
419  // paused then pause the profiling.
420  if (!m_stack.back().status) {
421  pause();
422  }
423  }else {
424  // If the profiling was stopped, but the parent component should be profiled
425  // then resume profiling.
426  if (m_stack.back().status) {
427  resume();
428  }
429  }
430 }
431 
432 // Register the auditor
void start_profiling_component(const std::string &name)
std::map< std::string, __itt_event > TaskTypes
T empty(T...args)
The ISvcLocator is the interface implemented by the Service Factory in the Application Manager to loc...
Definition: ISvcLocator.h:25
const std::string & type() const
Access to the incident type.
Definition: Incident.h:41
MsgStream & info() const
shortcut for the method msgStream(MSG::INFO)
std::vector< std::string > m_algs_for_tasktypes
void skip_profiling_component(const std::string &name)
bool isExcluded(const std::string &name) const
T end(T...args)
bool isFailure() const
Test for a status code of FAILURE.
Definition: StatusCode.h:86
#define DECLARE_COMPONENT(type)
Definition: PluginService.h:36
void after(StandardEventType type, INamedInterface *i, const StatusCode &sc)
T setw(T...args)
virtual const std::string & name() const =0
Retrieve the name of the instance.
STL class.
StatusCode service(const Gaudi::Utils::TypeNameString &name, T *&svc, bool createIf=true)
Templated method to access a service by name.
Definition: ISvcLocator.h:78
std::vector< std::string > m_excluded
Property * declareProperty(const std::string &name, T &property, const std::string &doc="none") const
Declare the named property.
Definition: Auditor.h:232
string type
Definition: gaudirun.py:151
The interface implemented by any class wanting to listen to Incidents.
stack_entity(const std::string &name_, bool status_, const __itt_event event_=0, const __itt_event parent_event_=0)
This class is used for returning status codes from appropriate routines.
Definition: StatusCode.h:26
void after(StandardEventType, INamedInterface *, const StatusCode &) override
Definition: Auditor.cpp:107
IntelProfilerAuditor(const std::string &name, ISvcLocator *pSvcLocator)
T str(T...args)
SmartIF< ISvcLocator > & serviceLocator() const
The standard service locator.
Definition: Auditor.cpp:211
std::vector< stack_entity > m_stack
std::string stackIndent(bool newLevel=false) const
T insert(T...args)
IInterface compliant class extending IInterface with the name() method.
T find(T...args)
std::string taskTypeName(const std::string &component_name) const
T size(T...args)
MsgStream & debug() const
shortcut for the method msgStream(MSG::DEBUG)
T begin(T...args)
T c_str(T...args)
Base class for all Incidents (computing events).
Definition: Incident.h:17
virtual void addListener(IIncidentListener *lis, const std::string &type="", long priority=0, bool rethrow=false, bool singleShot=false)=0
Add listener.
const std::string & name() const override
Definition: Auditor.cpp:202
void before(StandardEventType type, INamedInterface *i)
bool isIncluded(const std::string &name) const
std::string typeName(const std::type_info &typ)
Definition: Dictionary.cpp:21
list i
Definition: ana.py:128
void before(StandardEventType, INamedInterface *) override
The following methods are meant to be implemented by the child class...
Definition: Auditor.cpp:87
MsgStream & endmsg(MsgStream &s)
MsgStream Modifier: endmsg. Calls the output method of the MsgStream.
Definition: MsgStream.h:244
The interface implemented by the IncidentSvc service.
Definition: IIncidentSvc.h:21
std::vector< std::string > m_included
Base class from which all concrete auditor classes should be derived.
Definition: Auditor.h:35
void handle(const Incident &incident)
Inform that a new incident has occurred.