| The Gaudi Framework v32r1 (f65d50dc)

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