The Gaudi Framework  v33r1 (b1225454)
GoogleAuditor.cpp
Go to the documentation of this file.
1 /***********************************************************************************\
2 * (c) Copyright 1998-2019 CERN for the benefit of the LHCb and ATLAS collaborations *
3 * *
4 * This software is distributed under the terms of the Apache version 2 licence, *
5 * copied verbatim in the file "LICENSE". *
6 * *
7 * In applying this licence, CERN does not waive the privileges and immunities *
8 * granted to it by virtue of its status as an Intergovernmental Organization *
9 * or submit itself to any jurisdiction. *
10 \***********************************************************************************/
11 
12 #include <algorithm>
13 #include <memory>
14 #include <string>
15 #include <utility>
16 #include <vector>
17 
18 #include "GaudiKernel/Auditor.h"
23 #include "GaudiKernel/MsgStream.h"
24 
26 #include "GaudiAlg/Sequencer.h"
27 
28 #ifdef TCMALLOC_OLD_GOOGLE_HEADERS
29 # include "google/heap-checker.h"
30 # include "google/heap-profiler.h"
31 # include "google/profiler.h"
32 #else
33 # include "gperftools/heap-checker.h"
34 # include "gperftools/heap-profiler.h"
35 # include "gperftools/profiler.h"
36 #endif
37 
38 namespace Google {
39 
47  class AuditorBase : public extends<Auditor, IIncidentListener> {
48 
49  public:
51  using extends::extends;
52 
54  StatusCode initialize() override {
55  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
63  std::sort( m_when.begin(), m_when.end() );
64  std::sort( m_veto.begin(), m_veto.end() );
65  std::sort( m_list.begin(), m_list.end() );
66 
67  return StatusCode::SUCCESS;
68  }
69 
71  StatusCode finalize() override {
72  if ( alreadyRunning() ) stopAudit();
73  return StatusCode::SUCCESS;
74  }
75 
76  private:
78  inline void startAudit() {
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  info() << " -> Stopping full audit" << endmsg;
91  t << "FULL-Events" << m_nEvts << "To" << m_nEvts + m_nSampleEvents;
92  google_after( t.str() );
93  m_inFullAudit = false;
95  }
96 
99  inline bool isSequencer( INamedInterface* i ) const {
100  return ( dynamic_cast<GaudiSequencer*>( i ) != NULL || dynamic_cast<Sequencer*>( i ) != NULL );
101  }
102 
104  inline bool isPhaseEnabled( CustomEventTypeRef type ) const {
105  return ( std::find( m_when.begin(), m_when.end(), type ) != m_when.end() );
106  }
107 
109  inline bool isComponentEnabled( std::string_view name ) const {
110  return ( std::find( m_veto.begin(), m_veto.end(), name ) == m_veto.end() &&
111  ( m_list.empty() || std::find( m_list.begin(), m_list.end(), name ) != m_list.end() ) );
112  }
113 
114  // Construct the dump name based on processing phase and component name
115  std::string getDumpName( CustomEventTypeRef type, std::string_view name ) const {
117  t << name << "-" << type;
118  if ( type == "Execute" ) t << "-Event" << m_nEvts;
119  return t.str();
120  }
121 
122  public:
128  void handle( const Incident& incident ) override {
129  if ( IncidentType::BeginEvent == incident.type() ) {
130  ++m_nEvts;
131  m_audit = ( m_nEvts > m_eventsToSkip && ( m_freq < 0 || m_nEvts == 1 || m_nEvts % m_freq == 0 ) );
132  if ( UNLIKELY( msgLevel( MSG::DEBUG ) ) ) debug() << "Event " << m_nEvts << " Audit=" << m_audit << endmsg;
133  if ( m_fullEventAudit ) {
134  if ( m_inFullAudit ) {
136  stopAudit();
137  } else {
139  }
140  }
141  if ( m_audit && !m_inFullAudit && !alreadyRunning() ) { startAudit(); }
142  }
143  }
144  }
145 
146  public:
147  void before( StandardEventType type, INamedInterface* i ) override {
148  if ( !m_skipSequencers || !isSequencer( i ) ) { before( type, i->name() ); }
149  }
150 
151  void before( CustomEventTypeRef type, INamedInterface* i ) override {
152  if ( !m_skipSequencers || !isSequencer( i ) ) { before( type, i->name() ); }
153  }
154 
155  void before( StandardEventType type, const std::string& s ) override {
157  t << type;
158  before( t.str(), s );
159  }
160 
161  void before( CustomEventTypeRef type, const std::string& s ) override {
163  if ( !alreadyRunning() ) {
164  info() << "Starting Auditor for " << s << ":" << type << endmsg;
165  m_startedBy = s;
167  } else {
168  warning() << "Auditor already running. Cannot be started for " << s << endmsg;
169  }
170  }
171  }
172 
173  void after( StandardEventType type, INamedInterface* i, const StatusCode& sc ) override {
174  if ( !m_skipSequencers || !isSequencer( i ) ) {
176  t << type;
177  after( t.str(), i, sc );
178  }
179  }
180 
181  void after( CustomEventTypeRef type, INamedInterface* i, const StatusCode& sc ) override {
182  if ( !m_skipSequencers || !isSequencer( i ) ) { after( type, i->name(), sc ); }
183  }
184 
185  void after( StandardEventType type, const std::string& s, const StatusCode& sc ) override {
187  t << type;
188  after( t.str(), s, sc );
189  }
190 
191  void after( CustomEventTypeRef type, const std::string& s, const StatusCode& ) override {
193  if ( s == m_startedBy ) { google_after( getDumpName( type, s ) ); }
194  }
195  }
196 
197  // Obsolete methods
198  void beforeInitialize( INamedInterface* i ) override { return before( IAuditor::Initialize, i ); }
199  void beforeReinitialize( INamedInterface* i ) override { return before( IAuditor::ReInitialize, i ); }
200  void beforeExecute( INamedInterface* i ) override { return before( IAuditor::Execute, i ); }
201  void beforeFinalize( INamedInterface* i ) override { return before( IAuditor::Finalize, i ); }
202 
203  void afterInitialize( INamedInterface* i ) override {
205  }
206  void afterReinitialize( INamedInterface* i ) override {
208  }
209  void afterExecute( INamedInterface* i, const StatusCode& s ) override { return after( IAuditor::Execute, i, s ); }
211 
212  protected:
214  virtual void google_before( const std::string& s ) = 0;
215 
217  virtual void google_after( const std::string& s ) = 0;
218 
220  virtual bool alreadyRunning() = 0;
221 
222  private:
224  "ActivateAt",
225  {"Initialize", "ReInitialize", "Execute", "Finalize"},
226  "List of phases to activate the Auditoring during"};
228  this, "DisableFor", {}, "List of component names to disable the auditing for"};
230  this, "EnableFor", {}, "Any component in this list will be audited. If empty, all will be done."};
231  Gaudi::Property<int> m_freq{this, "ProfileFreq", -1, "The frequence to audit events. -1 means all events"};
233  this, "DoFullEventProfile", false,
234  "If true, instead of individually auditing components, the full event (or events) will be audited in one go"};
236  this, "FullEventNSampleEvents", 1, "The number of events to include in a full event audit, if enabled"};
238  "Number of events to skip before activating the auditing"};
239  Gaudi::Property<bool> m_skipSequencers{this, "SkipSequencers", true,
240  "If true, auditing will be skipped for Sequencer objects."};
241 
242  bool m_audit = true;
243  unsigned long long m_nEvts = 0;
244  unsigned long long m_sampleEventCount =
245  0;
246  bool m_inFullAudit = false;
248  };
249 
263  class HeapProfiler : public AuditorBase {
264 
265  public:
267  using AuditorBase::AuditorBase;
268 
269  protected:
270  void google_before( const std::string& s ) override { HeapProfilerStart( s.c_str() ); }
271 
272  void google_after( const std::string& s ) override {
273  if ( m_dumpProfileHeaps ) { HeapProfilerDump( s.c_str() ); }
274  if ( m_printProfilesToLog ) {
275  const char* profile = GetHeapProfile();
276  info() << profile << endmsg;
277  delete profile;
278  }
279  HeapProfilerStop();
280  }
281 
282  bool alreadyRunning() override { return IsHeapProfilerRunning(); }
283 
284  private:
285  Gaudi::Property<bool> m_dumpProfileHeaps{this, "DumpHeapProfiles", true, ""};
286  Gaudi::Property<bool> m_printProfilesToLog{this, "PrintProfilesToLog", false, ""};
287  };
288 
302  class HeapChecker : public AuditorBase {
303 
304  public:
306  using AuditorBase::AuditorBase;
307 
308  StatusCode initialize() override {
309  const StatusCode sc = AuditorBase::initialize();
310  if ( sc.isFailure() ) return sc;
311 
312  const char* HEAPCHECK = getenv( "HEAPCHECK" );
313  if ( !HEAPCHECK ) {
314  fatal() << "Environment variable HEAPCHECK must be set to 'local'" << endmsg;
315  return StatusCode::FAILURE;
316  }
317  if ( std::string( HEAPCHECK ) != "local" ) {
318  warning() << "Environment variable HEAPCHECK is set to " << HEAPCHECK
319  << " Partial Program Heap Checking is disabled" << endmsg;
320  m_enabled = false;
321  }
322 
323  return sc;
324  }
325 
326  protected:
327  void google_before( const std::string& s ) override {
328  if ( m_enabled && !m_checker ) { m_checker.reset( new HeapLeakChecker( s.c_str() ) ); }
329  }
330 
331  void google_after( const std::string& s ) override {
332  if ( m_enabled && m_checker ) {
333  if ( !m_checker->NoLeaks() ) { warning() << "Leak detected for " << s << endmsg; }
334  m_checker.reset();
335  }
336  }
337 
338  bool alreadyRunning() override { return m_enabled && m_checker; }
339 
340  private:
341  bool m_enabled = true;
343  };
344 
358  class CPUProfiler : public AuditorBase {
359 
360  public:
361  using AuditorBase::AuditorBase;
362 
363  protected:
364  void google_before( const std::string& s ) override {
365  if ( !m_running ) {
366  m_running = true;
367  ProfilerStart( ( s + ".prof" ).c_str() );
368  }
369  }
370 
371  void google_after( const std::string& ) override {
372  if ( m_running ) {
373  ProfilerStop();
374  m_running = false;
375  }
376  }
377 
378  bool alreadyRunning() override { return m_running; }
379 
380  private:
381  bool m_running = false;
382  };
383 
387 } // namespace Google
void afterReinitialize(INamedInterface *i) override
Gaudi::Property< std::vector< std::string > > m_list
#define UNLIKELY(x)
Definition: Kernel.h:106
bool isPhaseEnabled(CustomEventTypeRef type) const
Check if auditing is enabled for the current processing phase.
std::string m_startedBy
Name of the component we are currently auditing.
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
void beforeFinalize(INamedInterface *i) override
std::unique_ptr< HeapLeakChecker > m_checker
Implementation of property with value of concrete type.
Definition: Property.h:370
MsgStream & warning() const
shortcut for the method msgStream(MSG::WARNING)
virtual void google_before(const std::string &s)=0
Start the google tool.
const std::string & type() const
Access to the incident type.
Definition: Incident.h:48
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.
bool isSequencer(INamedInterface *i) const
Check if the component in question is a GaudiSequencer or a Sequencer.
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< bool > m_dumpProfileHeaps
Gaudi::Property< int > m_freq
constexpr static const auto SUCCESS
Definition: StatusCode.h:100
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.
StatusCode finalize() override
Finalize the auditor base.
MsgStream & info() const
shortcut for the method msgStream(MSG::INFO)
SmartIF< ISvcLocator > & serviceLocator() const override
The standard service locator.
Definition: Auditor.cpp:192
bool m_inFullAudit
Internal flag to indicate if we are current in a full event audit.
void google_after(const std::string &s) override
stop the google tool
Gaudi::Property< bool > m_printProfilesToLog
unsigned long long m_sampleEventCount
Internal count of the number of events currently processed during an audit.
MSG::Level msgLevel() const
get the cached level (originally extracted from the embedded MsgStream)
virtual const std::string & name() const =0
Retrieve the name of the instance.
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:86
void before(CustomEventTypeRef type, INamedInterface *i) override
unsigned long long m_nEvts
Number of events processed.
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:61
void afterExecute(INamedInterface *i, const StatusCode &s) override
Auditor using the Google Heap Checker.
void before(CustomEventTypeRef type, const std::string &s) override
T str(T... args)
MsgStream & debug() const
shortcut for the method msgStream(MSG::DEBUG)
void beforeInitialize(INamedInterface *i) override
T reset(T... args)
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 afterInitialize(INamedInterface *i) override
void beforeReinitialize(INamedInterface *i) override
bool isComponentEnabled(std::string_view name) const
Check if auditing is enabled for the given component.
Base class used to extend a class implementing other interfaces.
Definition: extends.h:20
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.
Base class for all Incidents (computing events).
Definition: Incident.h:27
Gaudi::Property< bool > m_skipSequencers
const std::string & name() const override
Definition: Auditor.cpp:188
string s
Definition: gaudirun.py:328
constexpr static const auto FAILURE
Definition: StatusCode.h:101
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)
bool isFailure() const
Definition: StatusCode.h:145
Base for Google Auditors.
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
MsgStream & fatal() const
shortcut for the method msgStream(MSG::FATAL)
std::string getDumpName(CustomEventTypeRef type, std::string_view name) const
MsgStream & endmsg(MsgStream &s)
MsgStream Modifier: endmsg. Calls the output method of the MsgStream.
Definition: MsgStream.h:202
The interface implemented by the IncidentSvc service.
Definition: IIncidentSvc.h:33
void after(StandardEventType type, INamedInterface *i, const StatusCode &sc) override
Auditor based on the Google Heap Profiler.
Gaudi::Property< std::vector< std::string > > m_veto