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"
11 #include "GaudiKernel/MsgStream.h"
14 
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 extends<Auditor,
41  IIncidentListener>
42  {
43 
44  public:
45 
47  AuditorBase( const std::string& name, ISvcLocator* pSvcLocator);
48 
50  virtual ~AuditorBase() { }
51 
54  {
55  m_log << MSG::INFO << "Initialised" << endmsg;
56 
57  // add a listener for begin event
58  auto inSvc = serviceLocator()->service<IIncidentSvc>("IncidentSvc");
59  if ( !inSvc ) return StatusCode::FAILURE;
60  inSvc->addListener( this, IncidentType::BeginEvent );
61 
62  // sort various lists for speed when searching
66 
67  return StatusCode::SUCCESS;
68  }
69 
72  {
73  if ( alreadyRunning() ) stopAudit();
74  return StatusCode::SUCCESS;
75  }
76 
77  private:
78 
80  inline void startAudit()
81  {
82  m_log << MSG::INFO << " -> Starting full audit from event " << m_nEvts << " to "
84  m_inFullAudit = true;
87  t << "FULL-Events" << m_nEvts << "To" << m_nEvts+m_nSampleEvents ;
88  google_before(t.str());
89  }
90 
92  inline void stopAudit()
93  {
94  m_log << MSG::INFO << " -> Stopping full audit" << endmsg;
96  t << "FULL-Events" << m_nEvts << "To" << m_nEvts+m_nSampleEvents ;
97  google_after(t.str());
98  m_inFullAudit = false;
100  }
101 
104  inline bool isSequencer( INamedInterface* i ) const
105  {
106  return ( dynamic_cast<GaudiSequencer*>(i) != NULL ||
107  dynamic_cast<Sequencer*>(i) != NULL );
108  }
109 
111  inline bool isPhaseEnabled( CustomEventTypeRef type ) const
112  {
113  return ( std::find(m_when.begin(),m_when.end(),type) != m_when.end() );
114  }
115 
117  inline bool isComponentEnabled( const std::string& name ) const
118  {
119  return ( std::find(m_veto.begin(),m_veto.end(),name) == m_veto.end() &&
120  ( m_list.empty() ||
121  std::find(m_list.begin(),m_list.end(),name) != m_list.end() ) );
122  }
123 
124  // Construct the dump name based on processing phase and component name
125  std::string getDumpName( CustomEventTypeRef type,
126  const std::string& name ) const
127  {
129  t << name << "-" << type;
130  if ( type == "Execute" ) t << "-Event" << m_nEvts;
131  return t.str();
132  }
133 
134  public:
135 
141  void handle( const Incident& incident )
142  {
143  if ( IncidentType::BeginEvent == incident.type() )
144  {
145  ++m_nEvts;
147  ( m_freq < 0 ||
148  m_nEvts == 1 ||
149  m_nEvts % m_freq == 0 ) );
150  m_log << MSG::DEBUG << "Event " << m_nEvts
151  << " Audit=" << m_audit << endmsg;
152  if ( m_fullEventAudit )
153  {
154  if ( m_inFullAudit )
155  {
157  alreadyRunning() )
158  {
159  stopAudit();
160  }
161  else
162  {
164  }
165  }
166  if ( m_audit && !m_inFullAudit && !alreadyRunning() )
167  {
168  startAudit();
169  }
170  }
171  }
172  }
173 
174  public:
175 
176  void before(StandardEventType type, INamedInterface* i)
177  {
178  if ( !m_skipSequencers || !isSequencer(i) )
179  {
180  before( type, i->name() );
181  }
182  }
183 
184  void before(CustomEventTypeRef type, INamedInterface* i)
185  {
186  if ( !m_skipSequencers || !isSequencer(i) )
187  {
188  before( type, i->name() );
189  }
190  }
191 
192  void before(StandardEventType type, const std::string& s)
193  {
195  t << type;
196  before( t.str(), s );
197  }
198 
199  void before(CustomEventTypeRef type, const std::string& s)
200  {
201  if ( !m_fullEventAudit && m_audit &&
202  isPhaseEnabled(type) && isComponentEnabled(s) )
203  {
204  if ( !alreadyRunning() )
205  {
206  m_log << MSG::INFO
207  << "Starting Auditor for " << s << ":" << type
208  << endmsg;
209  m_startedBy = s;
210  google_before( getDumpName(type,s) );
211  }
212  else
213  {
215  << "Auditor already running. Cannot be started for " << s
216  << endmsg;
217  }
218  }
219  }
220 
221  void after(StandardEventType type, INamedInterface* i, const StatusCode& sc)
222  {
223  if ( !m_skipSequencers || !isSequencer(i) )
224  {
226  t << type;
227  after( t.str(), i, sc );
228  }
229  }
230 
231  void after(CustomEventTypeRef type, INamedInterface* i, const StatusCode& sc)
232  {
233  if ( !m_skipSequencers || !isSequencer(i) )
234  {
235  after( type, i->name(), sc );
236  }
237  }
238 
239  void after(StandardEventType type, const std::string& s, const StatusCode& sc)
240  {
242  t << type;
243  after( t.str(), s, sc );
244  }
245 
246  void after(CustomEventTypeRef type, const std::string& s, const StatusCode&)
247  {
248  if ( !m_fullEventAudit && m_audit &&
249  isPhaseEnabled(type) && isComponentEnabled(s) )
250  {
251  if ( s == m_startedBy ) { google_after( getDumpName(type,s) ); }
252  }
253  }
254 
255  // Obsolete methods
262 
269 
270  protected:
271 
273  virtual void google_before(const std::string& s) = 0;
274 
276  virtual void google_after(const std::string& s) = 0;
277 
279  virtual bool alreadyRunning() = 0;
280 
281  protected:
282 
283  mutable MsgStream m_log;
284 
285  private:
286 
290 
291  unsigned long long m_eventsToSkip;
292 
294 
295  int m_freq;
296 
297  bool m_audit;
298 
299  unsigned long long m_nEvts;
300 
302 
303  unsigned long long m_nSampleEvents;
304 
305  unsigned long long m_sampleEventCount;
306 
308 
310 
311  };
312 
314  ISvcLocator* pSvcLocator )
315  : base_class ( name , pSvcLocator )
316  , m_log ( msgSvc() , name )
317  , m_audit ( true )
318  , m_nEvts ( 0 )
319  , m_sampleEventCount( 0 )
320  , m_inFullAudit ( false )
321  {
322  {
323  // Note: 'tmp' is needed to avoid an issue with list_of and C++11.
324  const std::vector<std::string> tmp =
325  boost::assign::list_of
326  ("Initialize")
327  ("ReInitialize")
328  ("Execute")
329  ("BeginRun")
330  ("EndRun")
331  ("Finalize");
332  m_when = tmp;
333  }
334 
335  declareProperty("ActivateAt", m_when,
336  "List of phases to activate the Auditoring during" );
337  declareProperty("DisableFor", m_veto,
338  "List of component names to disable the auditing for" );
339  declareProperty("EnableFor", m_list );
340  declareProperty("ProfileFreq", m_freq = -1,
341  "The frequence to audit events. -1 means all events" );
342  declareProperty("DoFullEventProfile", m_fullEventAudit = false,
343  "If true, instead of individually auditing components, the full event (or events) will be audited in one go" );
344  declareProperty("FullEventNSampleEvents", m_nSampleEvents = 1,
345  "The number of events to include in a full event audit, if enabled" );
346  declareProperty("SkipEvents", m_eventsToSkip = 0,
347  "Number of events to skip before activating the auditing" );
348  declareProperty("SkipSequencers", m_skipSequencers = true,
349  "If true, auditing will be skipped for Sequencer objects." );
350  }
351 
365  class HeapProfiler : public AuditorBase
366  {
367 
368  public:
369 
371  HeapProfiler( const std::string& name, ISvcLocator* pSvcLocator)
372  : AuditorBase( name, pSvcLocator )
373  {
374  declareProperty( "DumpHeapProfiles", m_dumpProfileHeaps = true );
375  declareProperty( "PrintProfilesToLog", m_printProfilesToLog = false );
376  }
377 
378  protected:
379 
381  {
382  HeapProfilerStart(s.c_str());
383  }
384 
386  {
387  if ( m_dumpProfileHeaps )
388  {
389  HeapProfilerDump(s.c_str());
390  }
391  if ( m_printProfilesToLog )
392  {
393  const char * profile = GetHeapProfile();
394  m_log << MSG::INFO << profile << endmsg;
395  delete profile;
396  }
397  HeapProfilerStop();
398  }
399 
400  bool alreadyRunning() { return IsHeapProfilerRunning(); }
401 
402  private:
403 
406 
407  };
408 
422  class HeapChecker : public AuditorBase
423  {
424 
425  public:
426 
428  HeapChecker( const std::string& name, ISvcLocator* pSvcLocator)
429  : AuditorBase ( name, pSvcLocator ),
430  m_enabled ( true ),
431  m_checker ( NULL )
432  { }
433 
434  virtual ~HeapChecker() { delete m_checker; }
435 
436  public:
437 
439  {
441  if ( sc.isFailure() ) return sc;
442 
443  const char * HEAPCHECK = getenv("HEAPCHECK");
444  if ( !HEAPCHECK )
445  {
446  m_log << MSG::FATAL
447  << "Environment variable HEAPCHECK must be set to 'local'"
448  << endmsg;
449  return StatusCode::FAILURE;
450  }
451  if ( std::string(HEAPCHECK) != "local" )
452  {
454  << "Environment variable HEAPCHECK is set to " << HEAPCHECK
455  << " Partial Program Heap Checking is disabled"
456  << endmsg;
457  m_enabled = false;
458  }
459 
460  return sc;
461  }
462 
463  protected:
464 
466  {
467  if ( m_enabled && !m_checker )
468  {
469  m_checker = new HeapLeakChecker(s.c_str());
470  }
471  }
472 
474  {
475  if ( m_enabled && m_checker )
476  {
477  if ( ! m_checker->NoLeaks() )
478  {
479  m_log << MSG::WARNING << "Leak detected for " << s << endmsg;
480  }
481  delete m_checker;
482  m_checker = NULL;
483  }
484  }
485 
486  bool alreadyRunning() { return m_enabled && m_checker != NULL ; }
487 
488  private:
489 
490  bool m_enabled;
491  HeapLeakChecker * m_checker;
492 
493  };
494 
508  class CPUProfiler : public AuditorBase
509  {
510 
511  public:
512 
513  CPUProfiler( const std::string& name, ISvcLocator* pSvcLocator )
514  : AuditorBase ( name, pSvcLocator ),
515  m_running ( false )
516  { }
517 
518  protected:
519 
521  {
522  if ( !m_running )
523  {
524  m_running = true;
525  ProfilerStart((s+".prof").c_str());
526  }
527  }
528 
530  {
531  if ( m_running )
532  {
533  ProfilerStop();
534  m_running = false;
535  }
536  }
537 
538  bool alreadyRunning() { return m_running; }
539 
540  private:
541 
542  bool m_running;
543 
544  };
545 
549 
550 }
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)
T empty(T...args)
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
const std::string & type() const
Access to the incident type.
Definition: Incident.h:41
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
T end(T...args)
StatusCode initialize()
Initialize the auditor base.
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.
#define DECLARE_COMPONENT(type)
Definition: PluginService.h:36
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.
STL class.
bool alreadyRunning()
check if we are already running the tool
StatusCode initialize()
Initialize the auditor base.
StatusCode service(const Gaudi::Utils::TypeNameString &name, T *&svc, bool createIf=true)
Templated method to access a service by name.
Definition: ISvcLocator.h:78
Property * declareProperty(const std::string &name, T &property, const std::string &doc="none") const
Declare the named property.
Definition: Auditor.h:232
void google_after(const std::string &)
stop the google tool
string type
Definition: gaudirun.py:151
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
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.
SmartIF< ISvcLocator > & serviceLocator() const
The standard service locator.
Definition: Auditor.cpp:211
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)
T find(T...args)
void beforeFinalize(INamedInterface *i)
Base class used to extend a class implementing other interfaces.
Definition: extends.h:10
T begin(T...args)
T c_str(T...args)
Base class for all Incidents (computing events).
Definition: Incident.h:17
void before(StandardEventType type, INamedInterface *i)
void handle(const Incident &incident)
Implement the handle method for the Incident service.
const std::string & name() const override
Definition: Auditor.cpp:202
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)
T sort(T...args)
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.
MsgStream & endmsg(MsgStream &s)
MsgStream Modifier: endmsg. Calls the output method of the MsgStream.
Definition: MsgStream.h:244
The interface implemented by the IncidentSvc service.
Definition: IIncidentSvc.h:21
void after(StandardEventType type, const std::string &s, const StatusCode &sc)
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.