The Gaudi Framework  v36r1 (3e2fb5a8)
IntelProfilerAuditor.cpp
Go to the documentation of this file.
1 /***********************************************************************************\
2 * (c) Copyright 1998-2019 CERN for the benefit of the LHCb and ATLAS collaborations *
3 * *
4 * This software is distributed under the terms of the Apache version 2 licence, *
5 * copied verbatim in the file "LICENSE". *
6 * *
7 * In applying this licence, CERN does not waive the privileges and immunities *
8 * granted to it by virtue of its status as an Intergovernmental Organization *
9 * or submit itself to any jurisdiction. *
10 \***********************************************************************************/
11 // ## Includes.
12 // * Standard libraries.
13 #include <algorithm>
14 #include <iomanip>
15 #include <memory>
16 #include <sstream>
17 #include <stack>
18 #include <string>
19 #include <utility>
20 #include <vector>
21 
22 // * Gaudi libraries.
23 #include "GaudiKernel/Auditor.h"
28 #include "GaudiKernel/MsgStream.h"
29 
30 // * Intel User API
31 #ifdef __GNUC__
32 # pragma GCC diagnostic ignored "-Wunused-function"
33 #endif
34 #include "ittnotify.h"
35 
37 
38 // Gaudi profiling auditor. The auditor use Intel API for control profiling
39 // flow. We need to run profiling throw Intel Amplifier amplxe-cl command
40 // line tool.
41 class IntelProfilerAuditor : public extends<Auditor, IIncidentListener> {
42 public:
43  // ## Public functions.
44  using extends::extends;
45  StatusCode initialize() override;
46  // Overridden functions.
47  void handle( const Incident& incident ) override;
48  using Auditor::before; // avoid hiding base-class methods
49  void before( StandardEventType type, INamedInterface* i ) override;
50  using Auditor::after; // avoid hiding base-class methods
51  void after( StandardEventType type, INamedInterface* i, const StatusCode& sc ) override;
52  // ## Private attributes.
53 private:
54  // Stack for store current component(algorithm) chain with useful
55  // information for the auditor.
56  struct stack_entity {
57  stack_entity( const std::string& name_, bool status_, const __itt_event event_ = 0,
58  const __itt_event parent_event_ = 0 )
59  : name( name_ ), status( status_ ), event( event_ ), parent_event( parent_event_ ) {}
60  // Name of the component.
62  // Running status: on/off.
63  bool status;
64  // Task type holder.
65  __itt_event event;
66  // Parent task type.
67  __itt_event parent_event;
68  };
69 
70 private:
71  Gaudi::Property<std::vector<std::string>> m_included{this, "IncludeAlgorithms", {}, "Names of included algorithms."};
72  Gaudi::Property<std::vector<std::string>> m_excluded{this, "ExcludeAlgorithms", {}, "Names of excluded algorithms."};
74  this, "StartFromEventN", 1, "After what event we stop profiling. If 0 than we also profile finalization stage."};
76  this, "StopAtEventN", 0,
77  "After what event we stop profiling. If 0 than we also profile finalization stage. Default = 0."};
79  this,
80  "ComponentsForTaskTypes",
81  {},
82  "Algorithm name, for which intel amplifier task type will be created."
83  "By default all algorithms have a corresponding task type."};
84  Gaudi::Property<std::string> m_alg_delim{this, "TaskTypeNameDelimeter", " ",
85  "The String delimiter between sequences/algorithms names in "
86  "\"Task Type\" grouping at Amplifier. Default=\" \"."};
87  Gaudi::Property<bool> m_enable_frames{this, "EnableFrames", false,
88  "Enable frames (needed for detecting slow events). Default=false."};
89  Gaudi::Property<int> m_frames_rate{this, "FramesRate", 100,
90  "Frames rate. The recommended maximum rate for calling the Frame API is "
91  "1000 frames (events) per second. A higher rate may result in large product"
92  " memory consumption and slow finalization. "
93  "You need update \"slow-frames-threshold\" and \"fast-frames-threshold\" "
94  "parameters of amplxe-cl tool to separate slow, medium and fast events. "
95  "For use frames you need to switch on \"EnableFrames\". "
96  "Default=100"};
97 
98 private:
99  // Events counter.
100  int m_nEvents = 0;
101  // Domain for event loop.
102  __itt_domain* domain = nullptr;
103  // True if profiler is started.
104  bool m_isStarted = false;
105  // Current stack of sequences/algorithms.
107  // Mapping of task type name to Amplifier event .
109 
110 private:
111  // ## Private functions.
114 
115  void start();
116  void pause();
117  void resume();
118  void stop();
119 
120  bool hasIncludes() const;
121  bool isIncluded( const std::string& name ) const;
122  bool isExcluded( const std::string& name ) const;
123  bool isRunning() const;
124 
125  int stackLevel() const;
126  std::string stackIndent( bool newLevel = false ) const;
127  std::string taskTypeName( const std::string& component_name ) const;
128 };
129 // ## Implementation.
131  m_isStarted = true;
132  __itt_resume();
133 }
134 
136  if ( !m_isStarted ) return;
138  __itt_event taskId = 0;
139  TaskTypes::const_iterator iter = m_tasktypes.find( typeName );
140  if ( iter != m_tasktypes.end() ) { taskId = iter->second; }
141 
142  if ( !taskId && m_algs_for_tasktypes.empty() ) {
143  // Create event
144  taskId = __itt_event_create( typeName.c_str(), typeName.size() );
145  m_tasktypes.insert( TaskTypes::value_type( typeName, taskId ) );
146  }
147 
148  stack_entity state = stack_entity( name, true, taskId );
149  stack_entity* parent = !m_stack.empty() ? &m_stack.back() : NULL;
150 
151  if ( parent != NULL ) {
152  if ( parent->event ) {
153  state.parent_event = parent->event;
154  } else {
155  state.parent_event = parent->parent_event;
156  }
157  }
158 
159  if ( taskId && state.parent_event ) {
160  debug() << stackIndent() << "Pause event " << state.parent_event << endmsg;
161  __itt_event_end( state.parent_event );
162  }
163  m_stack.push_back( state );
164 
165  debug() << stackIndent() << "Start profiling component " << typeName << endmsg;
166 
167  if ( taskId ) {
168  // Start event
169  debug() << stackIndent() << "Start event type " << state.event << " for " << typeName << endmsg;
170  __itt_event_start( state.event );
171  }
172 
173  __itt_resume();
174 }
175 
177  if ( !m_isStarted ) return;
178  debug() << stackIndent() << "Resume" << endmsg;
179  __itt_resume();
180 }
181 
183  if ( !m_isStarted ) return;
184  debug() << stackIndent() << "Pause" << endmsg;
185  __itt_pause();
186 }
187 
189  if ( !m_isStarted ) return;
190  m_stack.push_back( stack_entity( name, false ) );
191  debug() << stackIndent() << "Skip component " << name << endmsg;
192 }
193 
195  if ( !m_isStarted ) return;
196  m_isStarted = false;
197  __itt_pause();
198 }
199 
200 bool IntelProfilerAuditor::hasIncludes() const { return !m_included.empty(); }
201 
203  return std::find( m_included.begin(), m_included.end(), name ) != m_included.end();
204 }
205 
207  return std::find( m_excluded.begin(), m_excluded.end(), name ) != m_excluded.end();
208 }
209 
210 bool IntelProfilerAuditor::isRunning() const { return !m_stack.empty() && m_stack.back().status; }
211 
212 int IntelProfilerAuditor::stackLevel() const { return m_stack.size(); }
213 
216  indent << std::setw( stackLevel() * 2 + ( newLevel ? 2 : 0 ) ) << " ";
217  return indent.str();
218 }
219 
221  std::string result;
222  std::string delim = "";
223  for ( const auto& value : m_stack ) {
224  result += delim + value.name;
225  delim = m_alg_delim;
226  }
227  return result + m_alg_delim + component_name;
228 }
229 
231  info() << "Initialised" << endmsg;
232 
233  IIncidentSvc* inSvc = NULL;
234  const StatusCode sc = serviceLocator()->service( "IncidentSvc", inSvc );
235  if ( sc.isFailure() ) return sc;
236  // Useful to start profiling only after some event, we don't need profile
237  // initialization stage. For that we need to count events with BeginEvent
238  // listener.
239  inSvc->addListener( this, IncidentType::BeginEvent );
240  // If the end event number don't setup we finish profiling at the end
241  // of loop. We don't need profiling finalization stage.
242  inSvc->addListener( this, IncidentType::EndProcessing );
243 
244  std::string str_excluded, str_included, str_eventtypes;
245  for ( const auto& name : m_excluded ) { str_excluded += " " + name; }
246  for ( const auto& name : m_included ) { str_included += " " + name; }
247  for ( const auto& name : m_algs_for_tasktypes ) { str_eventtypes += " " + name; }
248 
249  if ( !m_included.empty() ) {
250  info() << "Included algorithms (" << m_included.size() << "): " << str_included << endmsg;
251  }
252 
253  if ( !m_excluded.empty() ) {
254  info() << "Excluded algorithms (" << m_excluded.size() << "): " << str_excluded << endmsg;
255  }
256 
257  if ( !m_algs_for_tasktypes.empty() ) {
258  info() << "Event types (" << m_algs_for_tasktypes.size() << "): " << str_eventtypes << endmsg;
259  }
260 
261  // Create a profiler domain for detection of slow events.
262  domain = __itt_domain_create( "Event loop" );
263  domain->flags = m_enable_frames;
264 
265  return StatusCode::SUCCESS;
266 }
267 
268 void IntelProfilerAuditor::handle( const Incident& incident ) {
269  if ( IncidentType::BeginEvent != incident.type() ) return;
270  // Increment the event counter
271  ++m_nEvents;
272 
273  if ( m_nStartFromEvent == m_nEvents ) {
274  info() << "Start profiling (event #" << m_nEvents << ")" << endmsg;
275  start();
276  }
277 
278  if ( m_nStopAtEvent == m_nEvents ) {
279  info() << "Stop profiling (event #" << m_nEvents << ")" << endmsg;
280  stop();
281  }
282 }
283 
284 void IntelProfilerAuditor::before( StandardEventType type, INamedInterface* i ) {
285  // Skip unnecessary event types.
286  if ( !( ( type == IAuditor::Execute ) && m_isStarted ) ) return;
287 
288  // Name of the current component.
289  const std::string& name = i->name();
290  // debug() << "Before: " << name << " " << type << endmsg;
291 
292  if ( isRunning() ) {
293  if ( isExcluded( name ) ) {
294  // If profiling is running and component is explicitly excluded
295  // then skip component.
297  } else {
298  // If profiling is running and component is'not explicitly excluded
299  // then start profiling for component (add to stack).
301  }
302  } else {
303  if ( hasIncludes() ) {
304  // If the profiling is not running and "includes" is explicitly defined ...
305  if ( isIncluded( name ) ) {
306  // and the current component is in the include's list then start the
307  // component profiling.
309  } else {
310  // and the current component is not in the includes list then skip
311  // a profiling of the component.
313  }
314  } else {
315  // If "Includes" property isn't present and the component is ...
316  if ( isExcluded( name ) ) {
317  // in the excludes list then skip a profiling
319  } else {
320  // not in the exclude list then start a profiling
322  }
323  }
324  }
325  if ( m_nEvents % m_frames_rate == 0 ) { __itt_frame_begin_v3( domain, NULL ); }
326 }
327 
328 void IntelProfilerAuditor::after( StandardEventType type, INamedInterface* i, const StatusCode& /* sc*/ ) {
329  // Skip unnecessary event types
330  if ( !( ( type == IAuditor::Execute ) && m_isStarted ) ) return;
331 
332  if ( ( m_nEvents + 1 ) % m_frames_rate == 0 ) { __itt_frame_end_v3( domain, NULL ); }
333 
334  // Name of the current component
335  const std::string& name = i->name();
336  stack_entity state = m_stack.back();
337  // Remove component from stack.
338  m_stack.pop_back();
339 
340  if ( state.event != 0 ) {
341  debug() << stackIndent( true ) << "End event for " << name << endmsg;
342  __itt_event_end( state.event );
343 
344  if ( state.parent_event != 0 ) {
345  debug() << stackIndent() << "Resume event for " << state.parent_event << endmsg;
346  __itt_event_start( state.parent_event );
347  }
348  }
349 
350  if ( m_stack.empty() ) {
351  // Pause if there are no parent components (top algorithm).
352  pause();
353  } else if ( state.status ) {
354  // If the profiling is running and we have parent component that is
355  // paused then pause the profiling.
356  if ( !m_stack.back().status ) { pause(); }
357  } else {
358  // If the profiling was stopped, but the parent component should be profiled
359  // then resume profiling.
360  if ( m_stack.back().status ) { resume(); }
361  }
362 }
363 
364 // Register the auditor
IntelProfilerAuditor::m_algs_for_tasktypes
Gaudi::Property< std::vector< std::string > > m_algs_for_tasktypes
Definition: IntelProfilerAuditor.cpp:78
IntelProfilerAuditor::before
void before(StandardEventType type, INamedInterface *i) override
Definition: IntelProfilerAuditor.cpp:284
IntelProfilerAuditor::resume
void resume()
Definition: IntelProfilerAuditor.cpp:176
IntelProfilerAuditor::stack_entity::name
std::string name
Definition: IntelProfilerAuditor.cpp:61
std::string
STL class.
IntelProfilerAuditor::m_included
Gaudi::Property< std::vector< std::string > > m_included
Definition: IntelProfilerAuditor.cpp:71
IAuditor::Execute
@ Execute
Definition: IAuditor.h:34
IntelProfilerAuditor::after
void after(StandardEventType type, INamedInterface *i, const StatusCode &sc) override
Definition: IntelProfilerAuditor.cpp:328
IIncidentSvc::addListener
virtual void addListener(IIncidentListener *lis, const std::string &type="", long priority=0, bool rethrow=false, bool singleShot=false)=0
Add listener.
IntelProfilerAuditor::skip_profiling_component
void skip_profiling_component(const std::string &name)
Definition: IntelProfilerAuditor.cpp:188
IntelProfilerAuditor::stackLevel
int stackLevel() const
Definition: IntelProfilerAuditor.cpp:212
IntelProfilerAuditor::m_isStarted
bool m_isStarted
Definition: IntelProfilerAuditor.cpp:104
GaudiException.h
IntelProfilerAuditor::start_profiling_component
void start_profiling_component(const std::string &name)
Definition: IntelProfilerAuditor.cpp:135
std::vector
STL class.
std::map::find
T find(T... args)
std::string::size
T size(T... args)
Auditor::before
void before(StandardEventType, INamedInterface *) override
The following methods are meant to be implemented by the child class...
Definition: Auditor.cpp:82
std::stringstream
STL class.
INamedInterface::name
virtual const std::string & name() const =0
Retrieve the name of the instance.
IntelProfilerAuditor::m_frames_rate
Gaudi::Property< int > m_frames_rate
Definition: IntelProfilerAuditor.cpp:89
IntelProfilerAuditor::domain
__itt_domain * domain
Definition: IntelProfilerAuditor.cpp:102
IntelProfilerAuditor::stack_entity::stack_entity
stack_entity(const std::string &name_, bool status_, const __itt_event event_=0, const __itt_event parent_event_=0)
Definition: IntelProfilerAuditor.cpp:57
IAuditorSvc.h
IntelProfilerAuditor::start
void start()
Definition: IntelProfilerAuditor.cpp:130
IIncidentSvc.h
Auditor::name
const std::string & name() const override
Definition: Auditor.cpp:192
IntelProfilerAuditor::m_excluded
Gaudi::Property< std::vector< std::string > > m_excluded
Definition: IntelProfilerAuditor.cpp:72
Auditor::after
void after(StandardEventType, INamedInterface *, const StatusCode &) override
Definition: Auditor.cpp:112
IntelProfilerAuditor::m_nEvents
int m_nEvents
Definition: IntelProfilerAuditor.cpp:100
TimingHistograms.name
name
Definition: TimingHistograms.py:23
StatusCode
Definition: StatusCode.h:65
IntelProfilerAuditor::initialize
StatusCode initialize() override
Definition: IntelProfilerAuditor.cpp:230
IntelProfilerAuditor::stack_entity
Definition: IntelProfilerAuditor.cpp:56
IntelProfilerAuditor::isRunning
bool isRunning() const
Definition: IntelProfilerAuditor.cpp:210
std::string::c_str
T c_str(T... args)
IntelProfilerAuditor::m_stack
std::vector< stack_entity > m_stack
Definition: IntelProfilerAuditor.cpp:106
IntelProfilerAuditor::m_tasktypes
TaskTypes m_tasktypes
Definition: IntelProfilerAuditor.cpp:108
endmsg
MsgStream & endmsg(MsgStream &s)
MsgStream Modifier: endmsg. Calls the output method of the MsgStream.
Definition: MsgStream.h:203
IntelProfilerAuditor::stack_entity::event
__itt_event event
Definition: IntelProfilerAuditor.cpp:65
IntelProfilerAuditor::handle
void handle(const Incident &incident) override
Definition: IntelProfilerAuditor.cpp:268
std::map< std::string, __itt_event >
extends
Base class used to extend a class implementing other interfaces.
Definition: extends.h:20
IntelProfilerAuditor::stack_entity::parent_event
__itt_event parent_event
Definition: IntelProfilerAuditor.cpp:67
StatusCode::isFailure
bool isFailure() const
Definition: StatusCode.h:142
gaudirun.type
type
Definition: gaudirun.py:154
INamedInterface
Definition: INamedInterface.h:25
IntelProfilerAuditor::stack_entity::status
bool status
Definition: IntelProfilerAuditor.cpp:63
StatusCode::SUCCESS
constexpr static const auto SUCCESS
Definition: StatusCode.h:100
GaudiDict::typeName
std::string typeName(const std::type_info &typ)
Definition: Dictionary.cpp:31
IntelProfilerAuditor::isExcluded
bool isExcluded(const std::string &name) const
Definition: IntelProfilerAuditor.cpp:206
compareRootHistos.state
def state
Definition: compareRootHistos.py:468
IIncidentListener.h
TaskTypes
std::map< std::string, __itt_event > TaskTypes
Definition: IntelProfilerAuditor.cpp:36
DECLARE_COMPONENT
#define DECLARE_COMPONENT(type)
Definition: PluginServiceV1.h:46
std::map::insert
T insert(T... args)
IntelProfilerAuditor::pause
void pause()
Definition: IntelProfilerAuditor.cpp:182
IntelProfilerAuditor::hasIncludes
bool hasIncludes() const
Definition: IntelProfilerAuditor.cpp:200
IntelProfilerAuditor::m_enable_frames
Gaudi::Property< bool > m_enable_frames
Definition: IntelProfilerAuditor.cpp:87
std::stringstream::str
T str(T... args)
Incident::type
const std::string & type() const
Access to the incident type.
Definition: Incident.h:48
std::map::end
T end(T... args)
IntelProfilerAuditor::m_alg_delim
Gaudi::Property< std::string > m_alg_delim
Definition: IntelProfilerAuditor.cpp:84
std::setw
T setw(T... args)
IntelProfilerAuditor::stop
void stop()
Definition: IntelProfilerAuditor.cpp:194
IIncidentSvc
Definition: IIncidentSvc.h:33
Incident
Definition: Incident.h:27
IntelProfilerAuditor::m_nStopAtEvent
Gaudi::Property< int > m_nStopAtEvent
Definition: IntelProfilerAuditor.cpp:75
IntelProfilerAuditor::isIncluded
bool isIncluded(const std::string &name) const
Definition: IntelProfilerAuditor.cpp:202
Auditor::serviceLocator
SmartIF< ISvcLocator > & serviceLocator() const override
The standard service locator.
Definition: Auditor.cpp:196
IntelProfilerAuditor::taskTypeName
std::string taskTypeName(const std::string &component_name) const
Definition: IntelProfilerAuditor.cpp:220
IntelProfilerAuditor
Definition: IntelProfilerAuditor.cpp:41
Gaudi::Property
Implementation of property with value of concrete type.
Definition: Property.h:39
IntelProfilerAuditor::stackIndent
std::string stackIndent(bool newLevel=false) const
Definition: IntelProfilerAuditor.cpp:214
MsgStream.h
PrepareBase.out
out
Definition: PrepareBase.py:20
IntelProfilerAuditor::m_nStartFromEvent
Gaudi::Property< int > m_nStartFromEvent
Definition: IntelProfilerAuditor.cpp:73
Auditor.h