All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
GoogleAuditor.cpp
Go to the documentation of this file.
1 
2 #include <vector>
3 #include <string>
4 #include <utility>
5 #include <memory>
6 #include <algorithm>
7 
8 #include "GaudiKernel/Auditor.h"
9 #include "GaudiKernel/IAuditorSvc.h"
10 #include "GaudiKernel/GaudiException.h"
11 #include "GaudiKernel/MsgStream.h"
12 #include "GaudiKernel/IIncidentListener.h"
13 #include "GaudiKernel/IIncidentSvc.h"
14 
15 #include "GaudiAlg/GaudiSequencer.h"
16 #include "GaudiAlg/Sequencer.h"
17 
18 #include "boost/assign/list_of.hpp"
19 
20 #ifdef TCMALLOC_OLD_GOOGLE_HEADERS
21 #include "google/heap-profiler.h"
22 #include "google/heap-checker.h"
23 #include "google/profiler.h"
24 #else
25 #include "gperftools/heap-profiler.h"
26 #include "gperftools/heap-checker.h"
27 #include "gperftools/profiler.h"
28 #endif
29 
30 namespace Google
31 {
32 
40  class AuditorBase : public extends1<Auditor, IIncidentListener>
41  {
42 
43  public:
44 
46  AuditorBase( const std::string& name, ISvcLocator* pSvcLocator);
47 
49  virtual ~AuditorBase() { }
50 
53  {
54  m_log << MSG::INFO << "Initialised" << endmsg;
55 
56  // add a listener for begin event
57  auto inSvc = serviceLocator()->service<IIncidentSvc>("IncidentSvc");
58  if ( !inSvc ) return StatusCode::FAILURE;
59  inSvc->addListener( this, IncidentType::BeginEvent );
60 
61  // sort various lists for speed when searching
62  std::sort( m_when.begin(), m_when.end() );
63  std::sort( m_veto.begin(), m_veto.end() );
64  std::sort( m_list.begin(), m_list.end() );
65 
66  return StatusCode::SUCCESS;
67  }
68 
71  {
72  if ( alreadyRunning() ) stopAudit();
73  return StatusCode::SUCCESS;
74  }
75 
76  private:
77 
79  inline void startAudit()
80  {
81  m_log << MSG::INFO << " -> Starting full audit from event " << m_nEvts << " to "
83  m_inFullAudit = true;
85  std::ostringstream t;
86  t << "FULL-Events" << m_nEvts << "To" << m_nEvts+m_nSampleEvents ;
87  google_before(t.str());
88  }
89 
91  inline void stopAudit()
92  {
93  m_log << MSG::INFO << " -> Stopping full audit" << endmsg;
94  std::ostringstream t;
95  t << "FULL-Events" << m_nEvts << "To" << m_nEvts+m_nSampleEvents ;
96  google_after(t.str());
97  m_inFullAudit = false;
99  }
100 
103  inline bool isSequencer( INamedInterface* i ) const
104  {
105  return ( dynamic_cast<GaudiSequencer*>(i) != NULL ||
106  dynamic_cast<Sequencer*>(i) != NULL );
107  }
108 
110  inline bool isPhaseEnabled( CustomEventTypeRef type ) const
111  {
112  return ( std::find(m_when.begin(),m_when.end(),type) != m_when.end() );
113  }
114 
116  inline bool isComponentEnabled( const std::string& name ) const
117  {
118  return ( std::find(m_veto.begin(),m_veto.end(),name) == m_veto.end() &&
119  ( m_list.empty() ||
120  std::find(m_list.begin(),m_list.end(),name) != m_list.end() ) );
121  }
122 
123  // Construct the dump name based on processing phase and component name
124  std::string getDumpName( CustomEventTypeRef type,
125  const std::string& name ) const
126  {
127  std::ostringstream t;
128  t << name << "-" << type;
129  if ( type == "Execute" ) t << "-Event" << m_nEvts;
130  return t.str();
131  }
132 
133  public:
134 
140  void handle( const Incident& incident )
141  {
142  if ( IncidentType::BeginEvent == incident.type() )
143  {
144  ++m_nEvts;
146  ( m_freq < 0 ||
147  m_nEvts == 1 ||
148  m_nEvts % m_freq == 0 ) );
149  m_log << MSG::DEBUG << "Event " << m_nEvts
150  << " Audit=" << m_audit << endmsg;
151  if ( m_fullEventAudit )
152  {
153  if ( m_inFullAudit )
154  {
156  alreadyRunning() )
157  {
158  stopAudit();
159  }
160  else
161  {
163  }
164  }
165  if ( m_audit && !m_inFullAudit && !alreadyRunning() )
166  {
167  startAudit();
168  }
169  }
170  }
171  }
172 
173  public:
174 
175  void before(StandardEventType type, INamedInterface* i)
176  {
177  if ( !m_skipSequencers || !isSequencer(i) )
178  {
179  before( type, i->name() );
180  }
181  }
182 
183  void before(CustomEventTypeRef type, INamedInterface* i)
184  {
185  if ( !m_skipSequencers || !isSequencer(i) )
186  {
187  before( type, i->name() );
188  }
189  }
190 
191  void before(StandardEventType type, const std::string& s)
192  {
193  std::ostringstream t;
194  t << type;
195  before( t.str(), s );
196  }
197 
198  void before(CustomEventTypeRef type, const std::string& s)
199  {
200  if ( !m_fullEventAudit && m_audit &&
201  isPhaseEnabled(type) && isComponentEnabled(s) )
202  {
203  if ( !alreadyRunning() )
204  {
205  m_log << MSG::INFO
206  << "Starting Auditor for " << s << ":" << type
207  << endmsg;
208  m_startedBy = s;
209  google_before( getDumpName(type,s) );
210  }
211  else
212  {
214  << "Auditor already running. Cannot be started for " << s
215  << endmsg;
216  }
217  }
218  }
219 
220  void after(StandardEventType type, INamedInterface* i, const StatusCode& sc)
221  {
222  if ( !m_skipSequencers || !isSequencer(i) )
223  {
224  std::ostringstream t;
225  t << type;
226  after( t.str(), i, sc );
227  }
228  }
229 
230  void after(CustomEventTypeRef type, INamedInterface* i, const StatusCode& sc)
231  {
232  if ( !m_skipSequencers || !isSequencer(i) )
233  {
234  after( type, i->name(), sc );
235  }
236  }
237 
238  void after(StandardEventType type, const std::string& s, const StatusCode& sc)
239  {
240  std::ostringstream t;
241  t << type;
242  after( t.str(), s, sc );
243  }
244 
245  void after(CustomEventTypeRef type, const std::string& s, const StatusCode&)
246  {
247  if ( !m_fullEventAudit && m_audit &&
248  isPhaseEnabled(type) && isComponentEnabled(s) )
249  {
250  if ( s == m_startedBy ) { google_after( getDumpName(type,s) ); }
251  }
252  }
253 
254  // Obsolete methods
261 
268 
269  protected:
270 
272  virtual void google_before(const std::string& s) = 0;
273 
275  virtual void google_after(const std::string& s) = 0;
276 
278  virtual bool alreadyRunning() = 0;
279 
280  protected:
281 
282  mutable MsgStream m_log;
283 
284  private:
285 
286  std::vector<std::string> m_when;
287  std::vector<std::string> m_veto;
288  std::vector<std::string> m_list;
289 
290  unsigned long long m_eventsToSkip;
291 
293 
294  int m_freq;
295 
296  bool m_audit;
297 
298  unsigned long long m_nEvts;
299 
301 
302  unsigned long long m_nSampleEvents;
303 
304  unsigned long long m_sampleEventCount;
305 
307 
308  std::string m_startedBy;
309 
310  };
311 
312  AuditorBase::AuditorBase( const std::string& name,
313  ISvcLocator* pSvcLocator )
314  : base_class ( name , pSvcLocator )
315  , m_log ( msgSvc() , name )
316  , m_audit ( true )
317  , m_nEvts ( 0 )
318  , m_sampleEventCount( 0 )
319  , m_inFullAudit ( false )
320  {
321  {
322  // Note: 'tmp' is needed to avoid an issue with list_of and C++11.
323  const std::vector<std::string> tmp =
324  boost::assign::list_of
325  ("Initialize")
326  ("ReInitialize")
327  ("Execute")
328  ("BeginRun")
329  ("EndRun")
330  ("Finalize");
331  m_when = tmp;
332  }
333 
334  declareProperty("ActivateAt", m_when,
335  "List of phases to activate the Auditoring during" );
336  declareProperty("DisableFor", m_veto,
337  "List of component names to disable the auditing for" );
338  declareProperty("EnableFor", m_list );
339  declareProperty("ProfileFreq", m_freq = -1,
340  "The frequence to audit events. -1 means all events" );
341  declareProperty("DoFullEventProfile", m_fullEventAudit = false,
342  "If true, instead of individually auditing components, the full event (or events) will be audited in one go" );
343  declareProperty("FullEventNSampleEvents", m_nSampleEvents = 1,
344  "The number of events to include in a full event audit, if enabled" );
345  declareProperty("SkipEvents", m_eventsToSkip = 0,
346  "Number of events to skip before activating the auditing" );
347  declareProperty("SkipSequencers", m_skipSequencers = true,
348  "If true, auditing will be skipped for Sequencer objects." );
349  }
350 
364  class HeapProfiler : public AuditorBase
365  {
366 
367  public:
368 
370  HeapProfiler( const std::string& name, ISvcLocator* pSvcLocator)
371  : AuditorBase( name, pSvcLocator )
372  {
373  declareProperty( "DumpHeapProfiles", m_dumpProfileHeaps = true );
374  declareProperty( "PrintProfilesToLog", m_printProfilesToLog = false );
375  }
376 
377  protected:
378 
379  void google_before(const std::string& s)
380  {
381  HeapProfilerStart(s.c_str());
382  }
383 
384  void google_after(const std::string& s)
385  {
386  if ( m_dumpProfileHeaps )
387  {
388  HeapProfilerDump(s.c_str());
389  }
390  if ( m_printProfilesToLog )
391  {
392  const char * profile = GetHeapProfile();
393  m_log << MSG::INFO << profile << endmsg;
394  delete profile;
395  }
396  HeapProfilerStop();
397  }
398 
399  bool alreadyRunning() { return IsHeapProfilerRunning(); }
400 
401  private:
402 
405 
406  };
407 
421  class HeapChecker : public AuditorBase
422  {
423 
424  public:
425 
427  HeapChecker( const std::string& name, ISvcLocator* pSvcLocator)
428  : AuditorBase ( name, pSvcLocator ),
429  m_enabled ( true ),
430  m_checker ( NULL )
431  { }
432 
433  virtual ~HeapChecker() { delete m_checker; }
434 
435  public:
436 
438  {
440  if ( sc.isFailure() ) return sc;
441 
442  const char * HEAPCHECK = getenv("HEAPCHECK");
443  if ( !HEAPCHECK )
444  {
445  m_log << MSG::FATAL
446  << "Environment variable HEAPCHECK must be set to 'local'"
447  << endmsg;
448  return StatusCode::FAILURE;
449  }
450  if ( std::string(HEAPCHECK) != "local" )
451  {
453  << "Environment variable HEAPCHECK is set to " << HEAPCHECK
454  << " Partial Program Heap Checking is disabled"
455  << endmsg;
456  m_enabled = false;
457  }
458 
459  return sc;
460  }
461 
462  protected:
463 
464  void google_before(const std::string& s)
465  {
466  if ( m_enabled && !m_checker )
467  {
468  m_checker = new HeapLeakChecker(s.c_str());
469  }
470  }
471 
472  void google_after(const std::string& s)
473  {
474  if ( m_enabled && m_checker )
475  {
476  if ( ! m_checker->NoLeaks() )
477  {
478  m_log << MSG::WARNING << "Leak detected for " << s << endmsg;
479  }
480  delete m_checker;
481  m_checker = NULL;
482  }
483  }
484 
485  bool alreadyRunning() { return m_enabled && m_checker != NULL ; }
486 
487  private:
488 
489  bool m_enabled;
490  HeapLeakChecker * m_checker;
491 
492  };
493 
507  class CPUProfiler : public AuditorBase
508  {
509 
510  public:
511 
512  CPUProfiler( const std::string& name, ISvcLocator* pSvcLocator )
513  : AuditorBase ( name, pSvcLocator ),
514  m_running ( false )
515  { }
516 
517  protected:
518 
519  void google_before(const std::string& s)
520  {
521  if ( !m_running )
522  {
523  m_running = true;
524  ProfilerStart((s+".prof").c_str());
525  }
526  }
527 
528  void google_after(const std::string&)
529  {
530  if ( m_running )
531  {
532  ProfilerStop();
533  m_running = false;
534  }
535  }
536 
537  bool alreadyRunning() { return m_running; }
538 
539  private:
540 
541  bool m_running;
542 
543  };
544 
548 
549 }
StatusCode finalize()
Finalize the auditor base.
HeapLeakChecker * m_checker
void beforeBeginRun(INamedInterface *i)
Definition of the MsgStream class used to transmit messages.
Definition: MsgStream.h:24
std::string m_startedBy
Name of the component we are currently auditing.
HeapChecker(const std::string &name, ISvcLocator *pSvcLocator)
Constructor.
void beforeReinitialize(INamedInterface *i)
void stopAudit()
stop a full event audit
The ISvcLocator is the interface implemented by the Service Factory in the Application Manager to loc...
Definition: ISvcLocator.h:25
MsgStream & endmsg(MsgStream &s)
MsgStream Modifier: endmsg. Calls the output method of the MsgStream.
Definition: MsgStream.h:244
const std::string & type() const
Access to the incident type.
Definition: Incident.h:34
virtual void google_before(const std::string &s)=0
Start the google tool.
virtual ~AuditorBase()
Destructor.
bool m_audit
Internal flag to say if auditing is enabled or not for the current event.
void before(CustomEventTypeRef type, const std::string &s)
void startAudit()
Start a full event audit.
unsigned long long m_nSampleEvents
Number of events to include in a full event audit.
virtual bool alreadyRunning()=0
check if we are already running the tool
StatusCode initialize()
bool m_inFullAudit
Internal flag to indicate if we are current in a full event audit.
bool isFailure() const
Test for a status code of FAILURE.
Definition: StatusCode.h:86
unsigned long long m_sampleEventCount
Internal count of the number of events currently processed during an audit.
int m_freq
The frequency to audit events. -1 means all events.
void before(CustomEventTypeRef type, INamedInterface *i)
virtual const std::string & name() const =0
Retrieve the name of the instance.
bool alreadyRunning()
check if we are already running the tool
StatusCode initialize()
Initialize the auditor base.
void google_after(const std::string &)
stop the google tool
void after(CustomEventTypeRef type, const std::string &s, const StatusCode &)
void afterExecute(INamedInterface *i, const StatusCode &s)
unsigned long long m_nEvts
Number of events processed.
void after(CustomEventTypeRef type, INamedInterface *i, const StatusCode &sc)
bool isPhaseEnabled(CustomEventTypeRef type) const
Check if auditing is enabled for the current processing phase.
void beforeExecute(INamedInterface *i)
void google_before(const std::string &s)
Start the google tool.
This class is used for returning status codes from appropriate routines.
Definition: StatusCode.h:26
#define DECLARE_COMPONENT(type)
Definition: PluginService.h:36
void google_after(const std::string &s)
stop the google tool
std::vector< std::string > m_list
Any component in this list will be audited. If empty, all will be done.
Auditor using the Google Heap Checker.
std::string getDumpName(CustomEventTypeRef type, const std::string &name) const
void afterBeginRun(INamedInterface *i)
bool m_fullEventAudit
Flag to indicate if full event auditing is enabled or not.
void google_before(const std::string &s)
Start the google tool.
void google_after(const std::string &s)
stop the google tool
bool alreadyRunning()
check if we are already running the tool
HeapProfiler(const std::string &name, ISvcLocator *pSvcLocator)
Constructor.
void afterFinalize(INamedInterface *i)
void afterReinitialize(INamedInterface *i)
void afterInitialize(INamedInterface *i)
std::vector< std::string > m_when
When to audit the algorithms.
void beforeEndRun(INamedInterface *i)
IInterface compliant class extending IInterface with the name() method.
void beforeInitialize(INamedInterface *i)
void beforeFinalize(INamedInterface *i)
Base class used to extend a class implementing other interfaces.
Definition: extends.h:10
Base class for all Incidents (computing events).
Definition: Incident.h:16
void before(StandardEventType type, INamedInterface *i)
void handle(const Incident &incident)
Implement the handle method for the Incident service.
string s
Definition: gaudirun.py:245
void google_before(const std::string &s)
Start the google tool.
MsgStream m_log
Messaging object.
void before(StandardEventType type, const std::string &s)
void after(StandardEventType type, INamedInterface *i, const StatusCode &sc)
CPUProfiler(const std::string &name, ISvcLocator *pSvcLocator)
std::vector< std::string > m_veto
Veto list. Any component in this list will not be audited.
AuditorBase(const std::string &name, ISvcLocator *pSvcLocator)
Constructor.
void afterEndRun(INamedInterface *i)
unsigned long long m_eventsToSkip
Number of events to skip before auditing.
Base for Google Auditors.
virtual void google_after(const std::string &s)=0
stop the google tool
bool alreadyRunning()
check if we are already running the tool
list i
Definition: ana.py:128
Auditor using the Google CPU Profiler.
bool m_skipSequencers
Boolean indicating if sequencers should be skipped or not.
The interface implemented by the IncidentSvc service.
Definition: IIncidentSvc.h:21
void after(StandardEventType type, const std::string &s, const StatusCode &sc)
string type
Definition: gaudirun.py:151
bool isComponentEnabled(const std::string &name) const
Check if auditing is enabled for the given component.
Auditor based on the Google Heap Profiler.
bool isSequencer(INamedInterface *i) const
Check if the component in question is a GaudiSequencer or a Sequencer.