The Gaudi Framework  master (37c0b60a)
IntelProfilerAuditor.cpp
Go to the documentation of this file.
1 /***********************************************************************************\
2 * (c) Copyright 1998-2024 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:
72  this, "IncludeAlgorithms", {}, "Names of included algorithms." };
74  this, "ExcludeAlgorithms", {}, "Names of excluded algorithms." };
76  this, "StartFromEventN", 1, "After what event we stop profiling. If 0 than we also profile finalization stage." };
78  this, "StopAtEventN", 0,
79  "After what event we stop profiling. If 0 than we also profile finalization stage. Default = 0." };
81  this,
82  "ComponentsForTaskTypes",
83  {},
84  "Algorithm name, for which intel amplifier task type will be created."
85  "By default all algorithms have a corresponding task type." };
86  Gaudi::Property<std::string> m_alg_delim{ this, "TaskTypeNameDelimeter", " ",
87  "The String delimiter between sequences/algorithms names in "
88  "\"Task Type\" grouping at Amplifier. Default=\" \"." };
89  Gaudi::Property<bool> m_enable_frames{ this, "EnableFrames", false,
90  "Enable frames (needed for detecting slow events). Default=false." };
91  Gaudi::Property<int> m_frames_rate{ this, "FramesRate", 100,
92  "Frames rate. The recommended maximum rate for calling the Frame API is "
93  "1000 frames (events) per second. A higher rate may result in large product"
94  " memory consumption and slow finalization. "
95  "You need update \"slow-frames-threshold\" and \"fast-frames-threshold\" "
96  "parameters of amplxe-cl tool to separate slow, medium and fast events. "
97  "For use frames you need to switch on \"EnableFrames\". "
98  "Default=100" };
99 
100 private:
101  // Events counter.
102  int m_nEvents = 0;
103  // Domain for event loop.
104  __itt_domain* domain = nullptr;
105  // True if profiler is started.
106  bool m_isStarted = false;
107  // Current stack of sequences/algorithms.
109  // Mapping of task type name to Amplifier event .
111 
112 private:
113  // ## Private functions.
116 
117  void start();
118  void pause();
119  void resume();
120  void stop();
121 
122  bool hasIncludes() const;
123  bool isIncluded( const std::string& name ) const;
124  bool isExcluded( const std::string& name ) const;
125  bool isRunning() const;
126 
127  int stackLevel() const;
128  std::string stackIndent( bool newLevel = false ) const;
129  std::string taskTypeName( const std::string& component_name ) const;
130 };
131 // ## Implementation.
133  m_isStarted = true;
134  __itt_resume();
135 }
136 
138  if ( !m_isStarted ) return;
140  __itt_event taskId = 0;
141  TaskTypes::const_iterator iter = m_tasktypes.find( typeName );
142  if ( iter != m_tasktypes.end() ) { taskId = iter->second; }
143 
144  if ( !taskId && m_algs_for_tasktypes.empty() ) {
145  // Create event
146  taskId = __itt_event_create( typeName.c_str(), typeName.size() );
147  m_tasktypes.insert( TaskTypes::value_type( typeName, taskId ) );
148  }
149 
150  stack_entity state = stack_entity( name, true, taskId );
151  stack_entity* parent = !m_stack.empty() ? &m_stack.back() : NULL;
152 
153  if ( parent != NULL ) {
154  if ( parent->event ) {
155  state.parent_event = parent->event;
156  } else {
157  state.parent_event = parent->parent_event;
158  }
159  }
160 
161  if ( taskId && state.parent_event ) {
162  debug() << stackIndent() << "Pause event " << state.parent_event << endmsg;
163  __itt_event_end( state.parent_event );
164  }
165  m_stack.push_back( state );
166 
167  debug() << stackIndent() << "Start profiling component " << typeName << endmsg;
168 
169  if ( taskId ) {
170  // Start event
171  debug() << stackIndent() << "Start event type " << state.event << " for " << typeName << endmsg;
172  __itt_event_start( state.event );
173  }
174 
175  __itt_resume();
176 }
177 
179  if ( !m_isStarted ) return;
180  debug() << stackIndent() << "Resume" << endmsg;
181  __itt_resume();
182 }
183 
185  if ( !m_isStarted ) return;
186  debug() << stackIndent() << "Pause" << endmsg;
187  __itt_pause();
188 }
189 
191  if ( !m_isStarted ) return;
192  m_stack.push_back( stack_entity( name, false ) );
193  debug() << stackIndent() << "Skip component " << name << endmsg;
194 }
195 
197  if ( !m_isStarted ) return;
198  m_isStarted = false;
199  __itt_pause();
200 }
201 
202 bool IntelProfilerAuditor::hasIncludes() const { return !m_included.empty(); }
203 
205  return std::find( m_included.begin(), m_included.end(), name ) != m_included.end();
206 }
207 
209  return std::find( m_excluded.begin(), m_excluded.end(), name ) != m_excluded.end();
210 }
211 
212 bool IntelProfilerAuditor::isRunning() const { return !m_stack.empty() && m_stack.back().status; }
213 
214 int IntelProfilerAuditor::stackLevel() const { return m_stack.size(); }
215 
218  indent << std::setw( stackLevel() * 2 + ( newLevel ? 2 : 0 ) ) << " ";
219  return indent.str();
220 }
221 
223  std::string result;
224  std::string delim = "";
225  for ( const auto& value : m_stack ) {
226  result += delim + value.name;
227  delim = m_alg_delim;
228  }
229  return result + m_alg_delim + component_name;
230 }
231 
233  info() << "Initialised" << endmsg;
234 
235  auto inSvc = serviceLocator()->service<IIncidentSvc>( "IncidentSvc" );
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:80
IntelProfilerAuditor::before
void before(StandardEventType type, INamedInterface *i) override
Definition: IntelProfilerAuditor.cpp:284
IntelProfilerAuditor::resume
void resume()
Definition: IntelProfilerAuditor.cpp:178
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:190
IntelProfilerAuditor::stackLevel
int stackLevel() const
Definition: IntelProfilerAuditor.cpp:214
IntelProfilerAuditor::m_isStarted
bool m_isStarted
Definition: IntelProfilerAuditor.cpp:106
GaudiException.h
IntelProfilerAuditor::start_profiling_component
void start_profiling_component(const std::string &name)
Definition: IntelProfilerAuditor.cpp:137
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:91
IntelProfilerAuditor::domain
__itt_domain * domain
Definition: IntelProfilerAuditor.cpp:104
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:132
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:73
Auditor::after
void after(StandardEventType, INamedInterface *, const StatusCode &) override
Definition: Auditor.cpp:112
IntelProfilerAuditor::m_nEvents
int m_nEvents
Definition: IntelProfilerAuditor.cpp:102
StatusCode
Definition: StatusCode.h:65
IntelProfilerAuditor::initialize
StatusCode initialize() override
Definition: IntelProfilerAuditor.cpp:232
IntelProfilerAuditor::stack_entity
Definition: IntelProfilerAuditor.cpp:56
IntelProfilerAuditor::isRunning
bool isRunning() const
Definition: IntelProfilerAuditor.cpp:212
std::string::c_str
T c_str(T... args)
IntelProfilerAuditor::m_stack
std::vector< stack_entity > m_stack
Definition: IntelProfilerAuditor.cpp:108
IntelProfilerAuditor::m_tasktypes
TaskTypes m_tasktypes
Definition: IntelProfilerAuditor.cpp:110
endmsg
MsgStream & endmsg(MsgStream &s)
MsgStream Modifier: endmsg. Calls the output method of the MsgStream.
Definition: MsgStream.h:202
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
gaudirun.type
type
Definition: gaudirun.py:160
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
ConditionsStallTest.name
name
Definition: ConditionsStallTest.py:77
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:208
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:184
IntelProfilerAuditor::hasIncludes
bool hasIncludes() const
Definition: IntelProfilerAuditor.cpp:202
IntelProfilerAuditor::m_enable_frames
Gaudi::Property< bool > m_enable_frames
Definition: IntelProfilerAuditor.cpp:89
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:86
std::setw
T setw(T... args)
compareRootHistos.state
state
Definition: compareRootHistos.py:496
IntelProfilerAuditor::stop
void stop()
Definition: IntelProfilerAuditor.cpp:196
IIncidentSvc
Definition: IIncidentSvc.h:33
Incident
Definition: Incident.h:27
IntelProfilerAuditor::m_nStopAtEvent
Gaudi::Property< int > m_nStopAtEvent
Definition: IntelProfilerAuditor.cpp:77
IntelProfilerAuditor::isIncluded
bool isIncluded(const std::string &name) const
Definition: IntelProfilerAuditor.cpp:204
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:222
IntelProfilerAuditor
Definition: IntelProfilerAuditor.cpp:41
Gaudi::Property
Implementation of property with value of concrete type.
Definition: Property.h:37
IntelProfilerAuditor::stackIndent
std::string stackIndent(bool newLevel=false) const
Definition: IntelProfilerAuditor.cpp:216
MsgStream.h
PrepareBase.out
out
Definition: PrepareBase.py:20
IntelProfilerAuditor::m_nStartFromEvent
Gaudi::Property< int > m_nStartFromEvent
Definition: IntelProfilerAuditor.cpp:75
Auditor.h