| # Gaudi Framework, version v25r0 |

Home |  | Generated: Mon Feb 17 2014

- Main Page
- Related Pages
- Modules
- Namespaces
- Classes
- Files

- File List
- File Members

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"
17 #include "GaudiKernel/IAuditorSvc.h"
18 #include "GaudiKernel/GaudiException.h"
19 #include "GaudiKernel/MsgStream.h"
20 #include "GaudiKernel/IIncidentListener.h"
21 #include "GaudiKernel/IIncidentSvc.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);
38 StatusCode initialize();
39 // Overridden functions.
40 void handle(const Incident& incident);
41 using Auditor::before; // avoid hiding base-class methods
42 void before(StandardEventType type, INamedInterface* i);
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.
67 int m_nStartFromEvent;
68 // After what event we stop profiling. If 0 than we also profile finalization
69 // stage. Default = 0.
70 int m_nStopAtEvent;
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).
81 bool m_enable_frames;
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.
87 int m_frames_rate;
88 private:
89 // Logger.
90 MsgStream m_log;
91 // Events counter.
92 int m_nEvents;
93 // Domain for event loop.
94 __itt_domain* domain;
95 // True if profiler is started.
96 bool m_isStarted;
97 // Current stack of sequences/algorithms.
98 std::vector<stack_entity> m_stack;
99 // Mapping of task type name to Amplifier event .
100 TaskTypes m_tasktypes;
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
122 IntelProfilerAuditor::IntelProfilerAuditor(const std::string& name,
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
161 void IntelProfilerAuditor::start() {
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
212 void IntelProfilerAuditor::resume() {
213 if (!m_isStarted) return;
214 m_log << MSG::DEBUG << stackIndent() << "Resume" << endmsg;
215 __itt_resume();
216 }
217
218 void IntelProfilerAuditor::pause() {
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
231 void IntelProfilerAuditor::stop() {
232 if (!m_isStarted) return;
233 m_isStarted = false;
234 __itt_pause();
235 }
236
237 bool IntelProfilerAuditor::hasIncludes() const {
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
251 bool IntelProfilerAuditor::isRunning() const {
252 return !m_stack.empty() && m_stack.back().status;
253 }
254
255 int IntelProfilerAuditor::stackLevel() const {
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
277 StatusCode IntelProfilerAuditor::initialize() {
278 m_log.setLevel(outputLevel());
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.
288 inSvc->addListener(this, IncidentType::BeginEvent);
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.
291 inSvc->addListener(this, IncidentType::EndProcessing);
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
350 void IntelProfilerAuditor::before(StandardEventType type, INamedInterface* i) {
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.
362 skip_profiling_component(name);
363 }else{
364 // If profiling is running and component is'not explicitly excluded
365 // then start profiling for component (add to stack).
366 start_profiling_component(name);
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.
374 start_profiling_component(name);
375 } else{
376 // and the current component is not in the includes list then skip
377 // a profiling of the component.
378 skip_profiling_component(name);
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
384 skip_profiling_component(name);
385 }else{
386 // not in the exclude list then start a profiling
387 start_profiling_component(name);
388 }
389 }
390 }
391 if (m_nEvents % m_frames_rate == 0) {
392 __itt_frame_begin_v3(domain, NULL);
393 }
394
395 }
396
397 void IntelProfilerAuditor::after(StandardEventType type,
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
444 DECLARE_COMPONENT(IntelProfilerAuditor)