The Gaudi Framework  v29r0 (ff2e7097)
GoogleAuditor.cpp
Go to the documentation of this file.
1 
2 #include <algorithm>
3 #include <memory>
4 #include <string>
5 #include <utility>
6 #include <vector>
7 
8 #include "GaudiKernel/Auditor.h"
13 #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-checker.h"
22 #include "google/heap-profiler.h"
23 #include "google/profiler.h"
24 #else
25 #include "gperftools/heap-checker.h"
26 #include "gperftools/heap-profiler.h"
27 #include "gperftools/profiler.h"
28 #endif
29 
30 namespace Google
31 {
32 
40  class AuditorBase : public extends<Auditor, IIncidentListener>
41  {
42 
43  public:
45  using extends::extends;
46 
48  ~AuditorBase() override = default;
49 
52  {
53  info() << "Initialised" << endmsg;
54 
55  // add a listener for begin event
56  auto inSvc = serviceLocator()->service<IIncidentSvc>( "IncidentSvc" );
57  if ( !inSvc ) return StatusCode::FAILURE;
58  inSvc->addListener( this, IncidentType::BeginEvent );
59 
60  // sort various lists for speed when searching
61  std::sort( m_when.begin(), m_when.end() );
62  std::sort( m_veto.begin(), m_veto.end() );
63  std::sort( m_list.begin(), m_list.end() );
64 
65  return StatusCode::SUCCESS;
66  }
67 
69  StatusCode finalize() override
70  {
71  if ( alreadyRunning() ) stopAudit();
72  return StatusCode::SUCCESS;
73  }
74 
75  private:
77  inline void startAudit()
78  {
79  info() << " -> Starting full audit from event " << m_nEvts << " to " << m_nEvts + m_nSampleEvents << endmsg;
80  m_inFullAudit = true;
83  t << "FULL-Events" << m_nEvts << "To" << m_nEvts + m_nSampleEvents;
84  google_before( t.str() );
85  }
86 
88  inline void stopAudit()
89  {
90  info() << " -> Stopping full audit" << endmsg;
92  t << "FULL-Events" << m_nEvts << "To" << m_nEvts + m_nSampleEvents;
93  google_after( t.str() );
94  m_inFullAudit = false;
96  }
97 
100  inline bool isSequencer( INamedInterface* i ) const
101  {
102  return ( dynamic_cast<GaudiSequencer*>( i ) != NULL || dynamic_cast<Sequencer*>( i ) != NULL );
103  }
104 
106  inline bool isPhaseEnabled( CustomEventTypeRef type ) const
107  {
108  return ( std::find( m_when.begin(), m_when.end(), type ) != m_when.end() );
109  }
110 
112  inline bool isComponentEnabled( const std::string& name ) const
113  {
114  return ( std::find( m_veto.begin(), m_veto.end(), name ) == m_veto.end() &&
115  ( m_list.empty() || std::find( m_list.begin(), m_list.end(), name ) != m_list.end() ) );
116  }
117 
118  // Construct the dump name based on processing phase and component name
119  std::string getDumpName( CustomEventTypeRef type, const std::string& name ) const
120  {
122  t << name << "-" << type;
123  if ( type == "Execute" ) t << "-Event" << m_nEvts;
124  return t.str();
125  }
126 
127  public:
133  void handle( const Incident& incident ) override
134  {
135  if ( IncidentType::BeginEvent == incident.type() ) {
136  ++m_nEvts;
137  m_audit = ( m_nEvts > m_eventsToSkip && ( m_freq < 0 || m_nEvts == 1 || m_nEvts % m_freq == 0 ) );
138  if ( UNLIKELY( msgLevel( MSG::DEBUG ) ) ) debug() << "Event " << m_nEvts << " Audit=" << m_audit << endmsg;
139  if ( m_fullEventAudit ) {
140  if ( m_inFullAudit ) {
142  stopAudit();
143  } else {
145  }
146  }
147  if ( m_audit && !m_inFullAudit && !alreadyRunning() ) {
148  startAudit();
149  }
150  }
151  }
152  }
153 
154  public:
155  void before( StandardEventType type, INamedInterface* i ) override
156  {
157  if ( !m_skipSequencers || !isSequencer( i ) ) {
158  before( type, i->name() );
159  }
160  }
161 
162  void before( CustomEventTypeRef type, INamedInterface* i ) override
163  {
164  if ( !m_skipSequencers || !isSequencer( i ) ) {
165  before( type, i->name() );
166  }
167  }
168 
169  void before( StandardEventType type, const std::string& s ) override
170  {
172  t << type;
173  before( t.str(), s );
174  }
175 
176  void before( CustomEventTypeRef type, const std::string& s ) override
177  {
178  if ( !m_fullEventAudit && m_audit && isPhaseEnabled( type ) && isComponentEnabled( s ) ) {
179  if ( !alreadyRunning() ) {
180  info() << "Starting Auditor for " << s << ":" << type << endmsg;
181  m_startedBy = s;
182  google_before( getDumpName( type, s ) );
183  } else {
184  warning() << "Auditor already running. Cannot be started for " << s << endmsg;
185  }
186  }
187  }
188 
189  void after( StandardEventType type, INamedInterface* i, const StatusCode& sc ) override
190  {
191  if ( !m_skipSequencers || !isSequencer( i ) ) {
193  t << type;
194  after( t.str(), i, sc );
195  }
196  }
197 
198  void after( CustomEventTypeRef type, INamedInterface* i, const StatusCode& sc ) override
199  {
200  if ( !m_skipSequencers || !isSequencer( i ) ) {
201  after( type, i->name(), sc );
202  }
203  }
204 
205  void after( StandardEventType type, const std::string& s, const StatusCode& sc ) override
206  {
208  t << type;
209  after( t.str(), s, sc );
210  }
211 
212  void after( CustomEventTypeRef type, const std::string& s, const StatusCode& ) override
213  {
214  if ( !m_fullEventAudit && m_audit && isPhaseEnabled( type ) && isComponentEnabled( s ) ) {
215  if ( s == m_startedBy ) {
216  google_after( getDumpName( type, s ) );
217  }
218  }
219  }
220 
221  // Obsolete methods
222  void beforeInitialize( INamedInterface* i ) override { return before( IAuditor::Initialize, i ); }
223  void beforeReinitialize( INamedInterface* i ) override { return before( IAuditor::ReInitialize, i ); }
224  void beforeExecute( INamedInterface* i ) override { return before( IAuditor::Execute, i ); }
225  void beforeBeginRun( INamedInterface* i ) override { return before( IAuditor::BeginRun, i ); }
226  void beforeEndRun( INamedInterface* i ) override { return before( IAuditor::EndRun, i ); }
227  void beforeFinalize( INamedInterface* i ) override { return before( IAuditor::Finalize, i ); }
228 
229  void afterInitialize( INamedInterface* i ) override
230  {
232  }
233  void afterReinitialize( INamedInterface* i ) override
234  {
236  }
237  void afterExecute( INamedInterface* i, const StatusCode& s ) override { return after( IAuditor::Execute, i, s ); }
241 
242  protected:
244  virtual void google_before( const std::string& s ) = 0;
245 
247  virtual void google_after( const std::string& s ) = 0;
248 
250  virtual bool alreadyRunning() = 0;
251 
252  private:
254  this,
255  "ActivateAt",
256  {"Initialize", "ReInitialize", "Execute", "BeginRun", "EndRun", "Finalize"},
257  "List of phases to activate the Auditoring during"};
259  this, "DisableFor", {}, "List of component names to disable the auditing for"};
261  this, "EnableFor", {}, "Any component in this list will be audited. If empty, all will be done."};
262  Gaudi::Property<int> m_freq{this, "ProfileFreq", -1, "The frequence to audit events. -1 means all events"};
264  this, "DoFullEventProfile", false,
265  "If true, instead of individually auditing components, the full event (or events) will be audited in one go"};
267  this, "FullEventNSampleEvents", 1, "The number of events to include in a full event audit, if enabled"};
269  "Number of events to skip before activating the auditing"};
270  Gaudi::Property<bool> m_skipSequencers{this, "SkipSequencers", true,
271  "If true, auditing will be skipped for Sequencer objects."};
272 
273  bool m_audit = true;
274  unsigned long long m_nEvts = 0;
275  unsigned long long m_sampleEventCount =
276  0;
277  bool m_inFullAudit = false;
279  };
280 
294  class HeapProfiler : public AuditorBase
295  {
296 
297  public:
299  using AuditorBase::AuditorBase;
300 
301  protected:
302  void google_before( const std::string& s ) override { HeapProfilerStart( s.c_str() ); }
303 
304  void google_after( const std::string& s ) override
305  {
306  if ( m_dumpProfileHeaps ) {
307  HeapProfilerDump( s.c_str() );
308  }
309  if ( m_printProfilesToLog ) {
310  const char* profile = GetHeapProfile();
311  info() << profile << endmsg;
312  delete profile;
313  }
314  HeapProfilerStop();
315  }
316 
317  bool alreadyRunning() override { return IsHeapProfilerRunning(); }
318 
319  private:
320  Gaudi::Property<bool> m_dumpProfileHeaps{this, "DumpHeapProfiles", true, ""};
321  Gaudi::Property<bool> m_printProfilesToLog{this, "PrintProfilesToLog", false, ""};
322  };
323 
337  class HeapChecker : public AuditorBase
338  {
339 
340  public:
342  using AuditorBase::AuditorBase;
343 
344  ~HeapChecker() override = default;
345 
346  public:
348  {
349  const StatusCode sc = AuditorBase::initialize();
350  if ( sc.isFailure() ) return sc;
351 
352  const char* HEAPCHECK = getenv( "HEAPCHECK" );
353  if ( !HEAPCHECK ) {
354  fatal() << "Environment variable HEAPCHECK must be set to 'local'" << endmsg;
355  return StatusCode::FAILURE;
356  }
357  if ( std::string( HEAPCHECK ) != "local" ) {
358  warning() << "Environment variable HEAPCHECK is set to " << HEAPCHECK
359  << " Partial Program Heap Checking is disabled" << endmsg;
360  m_enabled = false;
361  }
362 
363  return sc;
364  }
365 
366  protected:
367  void google_before( const std::string& s ) override
368  {
369  if ( m_enabled && !m_checker ) {
370  m_checker.reset( new HeapLeakChecker( s.c_str() ) );
371  }
372  }
373 
374  void google_after( const std::string& s ) override
375  {
376  if ( m_enabled && m_checker ) {
377  if ( !m_checker->NoLeaks() ) {
378  warning() << "Leak detected for " << s << endmsg;
379  }
380  m_checker.reset();
381  }
382  }
383 
384  bool alreadyRunning() override { return m_enabled && m_checker; }
385 
386  private:
387  bool m_enabled = true;
389  };
390 
404  class CPUProfiler : public AuditorBase
405  {
406 
407  public:
408  using AuditorBase::AuditorBase;
409 
410  protected:
411  void google_before( const std::string& s ) override
412  {
413  if ( !m_running ) {
414  m_running = true;
415  ProfilerStart( ( s + ".prof" ).c_str() );
416  }
417  }
418 
419  void google_after( const std::string& ) override
420  {
421  if ( m_running ) {
422  ProfilerStop();
423  m_running = false;
424  }
425  }
426 
427  bool alreadyRunning() override { return m_running; }
428 
429  private:
430  bool m_running = false;
431  };
432 
436 }
void afterReinitialize(INamedInterface *i) override
Gaudi::Property< std::vector< std::string > > m_list
#define UNLIKELY(x)
Definition: Kernel.h:128
std::string m_startedBy
Name of the component we are currently auditing.
void beforeBeginRun(INamedInterface *i) override
void google_after(const std::string &) override
stop the google tool
void stopAudit()
stop a full event audit
Gaudi::Property< std::vector< std::string > > m_when
const std::string & type() const
Access to the incident type.
Definition: Incident.h:41
void beforeFinalize(INamedInterface *i) override
std::unique_ptr< HeapLeakChecker > m_checker
Implementation of property with value of concrete type.
Definition: Property.h:319
MsgStream & info() const
shortcut for the method msgStream(MSG::INFO)
virtual void google_before(const std::string &s)=0
Start the google tool.
void google_after(const std::string &s) override
stop the google tool
bool m_audit
Internal flag to say if auditing is enabled or not for the current event.
~AuditorBase() override=default
Destructor.
void before(StandardEventType type, INamedInterface *i) override
void startAudit()
Start a full event audit.
void google_before(const std::string &s) override
Start the google tool.
Gaudi::Property< int > m_freq
void handle(const Incident &incident) override
Implement the handle method for the Incident service.
Gaudi::Property< bool > m_fullEventAudit
virtual bool alreadyRunning()=0
check if we are already running the tool
StatusCode initialize() override
Initialize the auditor base.
void afterBeginRun(INamedInterface *i) override
StatusCode finalize() override
Finalize 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
void google_after(const std::string &s) override
stop the google tool
unsigned long long m_sampleEventCount
Internal count of the number of events currently processed during an audit.
#define DECLARE_COMPONENT(type)
Definition: PluginService.h:33
STL class.
StatusCode service(const Gaudi::Utils::TypeNameString &name, T *&svc, bool createIf=true)
Templated method to access a service by name.
Definition: ISvcLocator.h:79
void before(CustomEventTypeRef type, INamedInterface *i) override
MsgStream & warning() const
shortcut for the method msgStream(MSG::WARNING)
unsigned long long m_nEvts
Number of events processed.
bool isPhaseEnabled(CustomEventTypeRef type) const
Check if auditing is enabled for the current processing phase.
void after(CustomEventTypeRef type, const std::string &s, const StatusCode &) override
bool alreadyRunning() override
check if we are already running the tool
This class is used for returning status codes from appropriate routines.
Definition: StatusCode.h:28
SmartIF< ISvcLocator > & serviceLocator() const override
The standard service locator.
Definition: Auditor.cpp:206
void afterExecute(INamedInterface *i, const StatusCode &s) override
Auditor using the Google Heap Checker.
std::string getDumpName(CustomEventTypeRef type, const std::string &name) const
void before(CustomEventTypeRef type, const std::string &s) override
void beforeInitialize(INamedInterface *i) override
Gaudi::Property< unsigned long long > m_nSampleEvents
bool alreadyRunning() override
check if we are already running the tool
IInterface compliant class extending IInterface with the name() method.
T find(T...args)
void beforeEndRun(INamedInterface *i) override
void afterInitialize(INamedInterface *i) override
void beforeReinitialize(INamedInterface *i) override
MsgStream & debug() const
shortcut for the method msgStream(MSG::DEBUG)
Base class used to extend a class implementing other interfaces.
Definition: extends.h:10
Gaudi::Property< unsigned long long > m_eventsToSkip
void before(StandardEventType type, const std::string &s) override
void google_before(const std::string &s) override
Start the google tool.
T c_str(T...args)
Base class for all Incidents (computing events).
Definition: Incident.h:17
Gaudi::Property< bool > m_skipSequencers
string s
Definition: gaudirun.py:253
void after(StandardEventType type, const std::string &s, const StatusCode &sc) override
void google_before(const std::string &s) override
Start the google tool.
void afterFinalize(INamedInterface *i) override
StatusCode initialize() override
Initialize the auditor base.
T sort(T...args)
Base for Google Auditors.
MsgStream & fatal() const
shortcut for the method msgStream(MSG::FATAL)
void beforeExecute(INamedInterface *i) override
MSG::Level msgLevel() const
get the output level from the embedded MsgStream
virtual void google_after(const std::string &s)=0
stop the google tool
void after(CustomEventTypeRef type, INamedInterface *i, const StatusCode &sc) override
Auditor using the Google CPU Profiler.
bool alreadyRunning() override
check if we are already running the tool
const std::string & name() const override
Definition: Auditor.cpp:202
MsgStream & endmsg(MsgStream &s)
MsgStream Modifier: endmsg. Calls the output method of the MsgStream.
Definition: MsgStream.h:209
virtual const std::string & name() const =0
Retrieve the name of the instance.
The interface implemented by the IncidentSvc service.
Definition: IIncidentSvc.h:23
void after(StandardEventType type, INamedInterface *i, const StatusCode &sc) override
bool isComponentEnabled(const std::string &name) const
Check if auditing is enabled for the given component.
Auditor based on the Google Heap Profiler.
void afterEndRun(INamedInterface *i) override
bool isSequencer(INamedInterface *i) const
Check if the component in question is a GaudiSequencer or a Sequencer.
Gaudi::Property< std::vector< std::string > > m_veto