The Gaudi Framework  v30r3 (a5ef0a68)
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 
49  {
50  info() << "Initialised" << endmsg;
51 
52  // add a listener for begin event
53  auto inSvc = serviceLocator()->service<IIncidentSvc>( "IncidentSvc" );
54  if ( !inSvc ) return StatusCode::FAILURE;
55  inSvc->addListener( this, IncidentType::BeginEvent );
56 
57  // sort various lists for speed when searching
58  std::sort( m_when.begin(), m_when.end() );
59  std::sort( m_veto.begin(), m_veto.end() );
60  std::sort( m_list.begin(), m_list.end() );
61 
62  return StatusCode::SUCCESS;
63  }
64 
66  StatusCode finalize() override
67  {
68  if ( alreadyRunning() ) stopAudit();
69  return StatusCode::SUCCESS;
70  }
71 
72  private:
74  inline void startAudit()
75  {
76  info() << " -> Starting full audit from event " << m_nEvts << " to " << m_nEvts + m_nSampleEvents << endmsg;
77  m_inFullAudit = true;
80  t << "FULL-Events" << m_nEvts << "To" << m_nEvts + m_nSampleEvents;
81  google_before( t.str() );
82  }
83 
85  inline void stopAudit()
86  {
87  info() << " -> Stopping full audit" << endmsg;
89  t << "FULL-Events" << m_nEvts << "To" << m_nEvts + m_nSampleEvents;
90  google_after( t.str() );
91  m_inFullAudit = false;
93  }
94 
97  inline bool isSequencer( INamedInterface* i ) const
98  {
99  return ( dynamic_cast<GaudiSequencer*>( i ) != NULL || dynamic_cast<Sequencer*>( i ) != NULL );
100  }
101 
103  inline bool isPhaseEnabled( CustomEventTypeRef type ) const
104  {
105  return ( std::find( m_when.begin(), m_when.end(), type ) != m_when.end() );
106  }
107 
109  inline bool isComponentEnabled( const std::string& name ) const
110  {
111  return ( std::find( m_veto.begin(), m_veto.end(), name ) == m_veto.end() &&
112  ( m_list.empty() || std::find( m_list.begin(), m_list.end(), name ) != m_list.end() ) );
113  }
114 
115  // Construct the dump name based on processing phase and component name
116  std::string getDumpName( CustomEventTypeRef type, const std::string& name ) const
117  {
119  t << name << "-" << type;
120  if ( type == "Execute" ) t << "-Event" << m_nEvts;
121  return t.str();
122  }
123 
124  public:
130  void handle( const Incident& incident ) override
131  {
132  if ( IncidentType::BeginEvent == incident.type() ) {
133  ++m_nEvts;
134  m_audit = ( m_nEvts > m_eventsToSkip && ( m_freq < 0 || m_nEvts == 1 || m_nEvts % m_freq == 0 ) );
135  if ( UNLIKELY( msgLevel( MSG::DEBUG ) ) ) debug() << "Event " << m_nEvts << " Audit=" << m_audit << endmsg;
136  if ( m_fullEventAudit ) {
137  if ( m_inFullAudit ) {
139  stopAudit();
140  } else {
142  }
143  }
144  if ( m_audit && !m_inFullAudit && !alreadyRunning() ) {
145  startAudit();
146  }
147  }
148  }
149  }
150 
151  public:
152  void before( StandardEventType type, INamedInterface* i ) override
153  {
154  if ( !m_skipSequencers || !isSequencer( i ) ) {
155  before( type, i->name() );
156  }
157  }
158 
159  void before( CustomEventTypeRef type, INamedInterface* i ) override
160  {
161  if ( !m_skipSequencers || !isSequencer( i ) ) {
162  before( type, i->name() );
163  }
164  }
165 
166  void before( StandardEventType type, const std::string& s ) override
167  {
169  t << type;
170  before( t.str(), s );
171  }
172 
173  void before( CustomEventTypeRef type, const std::string& s ) override
174  {
175  if ( !m_fullEventAudit && m_audit && isPhaseEnabled( type ) && isComponentEnabled( s ) ) {
176  if ( !alreadyRunning() ) {
177  info() << "Starting Auditor for " << s << ":" << type << endmsg;
178  m_startedBy = s;
179  google_before( getDumpName( type, s ) );
180  } else {
181  warning() << "Auditor already running. Cannot be started for " << s << endmsg;
182  }
183  }
184  }
185 
186  void after( StandardEventType type, INamedInterface* i, const StatusCode& sc ) override
187  {
188  if ( !m_skipSequencers || !isSequencer( i ) ) {
190  t << type;
191  after( t.str(), i, sc );
192  }
193  }
194 
195  void after( CustomEventTypeRef type, INamedInterface* i, const StatusCode& sc ) override
196  {
197  if ( !m_skipSequencers || !isSequencer( i ) ) {
198  after( type, i->name(), sc );
199  }
200  }
201 
202  void after( StandardEventType type, const std::string& s, const StatusCode& sc ) override
203  {
205  t << type;
206  after( t.str(), s, sc );
207  }
208 
209  void after( CustomEventTypeRef type, const std::string& s, const StatusCode& ) override
210  {
211  if ( !m_fullEventAudit && m_audit && isPhaseEnabled( type ) && isComponentEnabled( s ) ) {
212  if ( s == m_startedBy ) {
213  google_after( getDumpName( type, s ) );
214  }
215  }
216  }
217 
218  // Obsolete methods
219  void beforeInitialize( INamedInterface* i ) override { return before( IAuditor::Initialize, i ); }
220  void beforeReinitialize( INamedInterface* i ) override { return before( IAuditor::ReInitialize, i ); }
221  void beforeExecute( INamedInterface* i ) override { return before( IAuditor::Execute, i ); }
222  void beforeBeginRun( INamedInterface* i ) override { return before( IAuditor::BeginRun, i ); }
223  void beforeEndRun( INamedInterface* i ) override { return before( IAuditor::EndRun, i ); }
224  void beforeFinalize( INamedInterface* i ) override { return before( IAuditor::Finalize, i ); }
225 
226  void afterInitialize( INamedInterface* i ) override
227  {
229  }
230  void afterReinitialize( INamedInterface* i ) override
231  {
233  }
234  void afterExecute( INamedInterface* i, const StatusCode& s ) override { return after( IAuditor::Execute, i, s ); }
238 
239  protected:
241  virtual void google_before( const std::string& s ) = 0;
242 
244  virtual void google_after( const std::string& s ) = 0;
245 
247  virtual bool alreadyRunning() = 0;
248 
249  private:
251  this,
252  "ActivateAt",
253  {"Initialize", "ReInitialize", "Execute", "BeginRun", "EndRun", "Finalize"},
254  "List of phases to activate the Auditoring during"};
256  this, "DisableFor", {}, "List of component names to disable the auditing for"};
258  this, "EnableFor", {}, "Any component in this list will be audited. If empty, all will be done."};
259  Gaudi::Property<int> m_freq{this, "ProfileFreq", -1, "The frequence to audit events. -1 means all events"};
261  this, "DoFullEventProfile", false,
262  "If true, instead of individually auditing components, the full event (or events) will be audited in one go"};
264  this, "FullEventNSampleEvents", 1, "The number of events to include in a full event audit, if enabled"};
266  "Number of events to skip before activating the auditing"};
267  Gaudi::Property<bool> m_skipSequencers{this, "SkipSequencers", true,
268  "If true, auditing will be skipped for Sequencer objects."};
269 
270  bool m_audit = true;
271  unsigned long long m_nEvts = 0;
272  unsigned long long m_sampleEventCount =
273  0;
274  bool m_inFullAudit = false;
276  };
277 
291  class HeapProfiler : public AuditorBase
292  {
293 
294  public:
296  using AuditorBase::AuditorBase;
297 
298  protected:
299  void google_before( const std::string& s ) override { HeapProfilerStart( s.c_str() ); }
300 
301  void google_after( const std::string& s ) override
302  {
303  if ( m_dumpProfileHeaps ) {
304  HeapProfilerDump( s.c_str() );
305  }
306  if ( m_printProfilesToLog ) {
307  const char* profile = GetHeapProfile();
308  info() << profile << endmsg;
309  delete profile;
310  }
311  HeapProfilerStop();
312  }
313 
314  bool alreadyRunning() override { return IsHeapProfilerRunning(); }
315 
316  private:
317  Gaudi::Property<bool> m_dumpProfileHeaps{this, "DumpHeapProfiles", true, ""};
318  Gaudi::Property<bool> m_printProfilesToLog{this, "PrintProfilesToLog", false, ""};
319  };
320 
334  class HeapChecker : public AuditorBase
335  {
336 
337  public:
339  using AuditorBase::AuditorBase;
340 
342  {
343  const StatusCode sc = AuditorBase::initialize();
344  if ( sc.isFailure() ) return sc;
345 
346  const char* HEAPCHECK = getenv( "HEAPCHECK" );
347  if ( !HEAPCHECK ) {
348  fatal() << "Environment variable HEAPCHECK must be set to 'local'" << endmsg;
349  return StatusCode::FAILURE;
350  }
351  if ( std::string( HEAPCHECK ) != "local" ) {
352  warning() << "Environment variable HEAPCHECK is set to " << HEAPCHECK
353  << " Partial Program Heap Checking is disabled" << endmsg;
354  m_enabled = false;
355  }
356 
357  return sc;
358  }
359 
360  protected:
361  void google_before( const std::string& s ) override
362  {
363  if ( m_enabled && !m_checker ) {
364  m_checker.reset( new HeapLeakChecker( s.c_str() ) );
365  }
366  }
367 
368  void google_after( const std::string& s ) override
369  {
370  if ( m_enabled && m_checker ) {
371  if ( !m_checker->NoLeaks() ) {
372  warning() << "Leak detected for " << s << endmsg;
373  }
374  m_checker.reset();
375  }
376  }
377 
378  bool alreadyRunning() override { return m_enabled && m_checker; }
379 
380  private:
381  bool m_enabled = true;
383  };
384 
398  class CPUProfiler : public AuditorBase
399  {
400 
401  public:
402  using AuditorBase::AuditorBase;
403 
404  protected:
405  void google_before( const std::string& s ) override
406  {
407  if ( !m_running ) {
408  m_running = true;
409  ProfilerStart( ( s + ".prof" ).c_str() );
410  }
411  }
412 
413  void google_after( const std::string& ) override
414  {
415  if ( m_running ) {
416  ProfilerStop();
417  m_running = false;
418  }
419  }
420 
421  bool alreadyRunning() override { return m_running; }
422 
423  private:
424  bool m_running = false;
425  };
426 
430 }
void afterReinitialize(INamedInterface *i) override
Gaudi::Property< std::vector< std::string > > m_list
#define UNLIKELY(x)
Definition: Kernel.h:122
constexpr static const auto FAILURE
Definition: StatusCode.h:88
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:381
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.
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
Definition: StatusCode.h:139
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.
STL class.
#define DECLARE_COMPONENT(type)
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:51
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
constexpr static const auto SUCCESS
Definition: StatusCode.h:87
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
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.
MSG::Level msgLevel() const
get the cached level (originally extracted from the embedded MsgStream)
Gaudi::Property< std::vector< std::string > > m_veto