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