ATLAS Offline Software
ValgrindAuditor.cxx
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
3 */
4 
5 // $Id: ValgrindAuditor.cxx,v 1.4 2008-10-14 12:31:40 fwinkl Exp $
6 
7 // Package includes
8 #include "ValgrindAuditor.h"
9 
10 // Framework includes
11 #include "GaudiKernel/IIncidentSvc.h"
14 
15 // STL includes
16 #include <algorithm>
17 #include <iterator>
18 #include <limits>
19 
20 // Boost includes
21 #include <boost/algorithm/string.hpp>
22 
23 using std::string;
24 
25 // Constructor
27  ISvcLocator* pSvcLocator)
28  : Auditor(name, pSvcLocator),
29  m_valSvc("ValgrindSvc", this->name()),
30  m_eventCounter(0)
31 {
32  declareProperty("ProfiledAlgs", m_algs,
33  "List of algorithms to run in valgrind");
34 
35  declareProperty("ProfiledIntervals", m_intervals,
36  "Intervals to profile (e.g. 'MyAlg.initialize:MyAlg.finalize'" );
37 
38  declareProperty("IgnoreFirstNEvents", m_ignoreFirstNEvents = 0,
39  "Do not profile the first N events");
40 
41  declareProperty("DumpAfterEachInterval", m_dumpAfterEachInterval = true,
42  "Dump separate profile after each interval in ProfiledIntervals" );
43 }
44 
45 // Destructor
47 {
48 }
49 
50 
52 {
53  if ( !m_valSvc.retrieve().isSuccess()) {
54  msgStream() << MSG::ERROR << "Could not retrieve the ValgrindSvc" << endmsg;
55  return StatusCode::FAILURE;
56  }
57 
58  const IProperty* valSvcProp = dynamic_cast<const IProperty*>(&(*m_valSvc));
59  if ( !valSvcProp ) {
60  msgStream() << MSG::ERROR
61  << "Could not retrieve IProperty interface to ValgrindSvc."
62  << endmsg;
63  return StatusCode::FAILURE;
64  }
65 
66  // We inherit the OutputLevel from ValgrindSvc
67  ATH_CHECK(setProperty(valSvcProp->getProperty("OutputLevel")));
68 
69  msgStream() << MSG::VERBOSE
70  << "Initializing " << name() << "..."
71  << endmsg;
72 
73  // Copy some properties from ValgrindSvc
74  std::string properties[] = {"ProfiledAlgs",
75  "ProfiledIntervals",
76  "IgnoreFirstNEvents",
77  "DumpAfterEachInterval"};
78 
79  for( std::string prop : properties ) {
80  if ( !setProperty(valSvcProp->getProperty(prop)) ) {
81  msgStream() << MSG::ERROR << "Cannot set " << prop << " property." << endmsg;
82  return StatusCode::FAILURE;
83  }
84  }
85 
86  // Reset internal event counter
87  m_eventCounter = 0;
88 
89  // Create regular expressions from algorithm names
90  for( const std::string& re : m_algs ) {
91  try {
92  m_algsRegEx.push_back( boost::regex(re) );
93  }
94  catch ( const boost::regex_error& ) {
95  msgStream() << MSG::ERROR << "Ignoring invalid regular expression: " << re << endmsg;
96  }
97  }
98 
99  if ( msgLevel() <= MSG::INFO ) {
100  std::ostringstream out;
101  out << "[ ";
102  std::copy( m_algs.begin(), m_algs.end(),
103  std::ostream_iterator<std::string>( out, " " ) );
104  out << "]";
105  msgStream() << MSG::INFO << "Profiled algorithms: " << out.str() << endmsg;
106 
107  out.str("");
108  out << "[ ";
109  std::copy( m_intervals.begin(), m_intervals.end(),
110  std::ostream_iterator<std::string>( out, " " ) );
111  out << "]";
112  msgStream() << MSG::INFO << "Profiled intervals: " << out.str() << endmsg;
113  }
114 
115  if (!m_intervals.empty()) {
116  if ( decodeIntervals().isFailure() ) {
117  msgStream() << MSG::ERROR << "Syntax error in ProfiledIntervals" << endmsg;
118  return StatusCode::FAILURE;
119  }
120  }
121 
122  // Register incidents
123  ServiceHandle<IIncidentSvc> incSvc("IncidentSvc", this->name());
124  if ( !incSvc.retrieve().isSuccess() ) {
125  msgStream() << MSG::ERROR << "Unable to get the IncidentSvc" << endmsg;
126  return StatusCode::FAILURE;
127  }
128  // Try to be the first incident handler to be called
129  const long prio = std::numeric_limits<long>::max();
130 
131  incSvc->addListener( this, IncidentType::BeginEvent, prio );
132 
133  for( const std::pair<NameEvt,NameEvt>& h : m_hooks ) {
134  // No regular expressions allowed for incidents. Take the original string.
135  if ( h.first.second=="incident" ) incSvc->addListener( this, h.first.first.str(), prio );
136  if ( h.second.second=="incident" ) incSvc->addListener( this, h.second.first.str(), prio );
137  }
138 
139  return StatusCode::SUCCESS;
140 }
141 
142 
143 /********************************************************************************
144  * Incident handler
145  */
146 void ValgrindAuditor::handle( const Incident& inc )
147 {
148  // Internal event counter
149  if ( inc.type() == IncidentType::BeginEvent ) {
150  m_eventCounter++;
151  }
152 
153  // Check if the incident appears at beginning or end of interval
154  std::vector< std::pair<NameEvt,NameEvt> >::const_iterator h;
155  for (h=m_hooks.begin(); h!=m_hooks.end(); ++h) {
156  if ( h->first.second=="incident" ) do_before(inc.type(), "incident");
157  if ( h->second.second=="incident" ) do_after(inc.type(), "incident");
158  }
159 }
160 
161 
162 /********************************************************************************
163  * Gaudi auditor hooks
164  */
165 void ValgrindAuditor::before (StandardEventType evt, const std::string& name)
166 {
168  else {
169  std::ostringstream os;
170  os << evt;
171  do_before(name, boost::to_lower_copy(os.str()));
172  }
173 }
174 
175 void ValgrindAuditor::after (StandardEventType evt, const std::string& name, const StatusCode&)
176 {
178  else {
179  std::ostringstream os;
180  os << evt;
181  do_after(name, boost::to_lower_copy(os.str()));
182  }
183 }
184 
185 
186 /********************************************************************************
187  * Enable callgrind instrumentation before algorithm execution
188  */
189 void ValgrindAuditor::do_beforeExecute(const std::string& name)
190 {
191  if ( algMatch(name) ) {
193  if ( msgLevel() <= MSG::DEBUG )
194  msgStream() << MSG::DEBUG << "Starting callgrind before execute of " << name
195  << " [event #" << m_eventCounter << "]" << endmsg;
196 
197  m_valSvc->callgrindStartInstrumentation();
198  }
199  }
200 }
201 
202 
203 /********************************************************************************
204  * Disable callgrind instrumentation after algorithm execution
205  */
206 void ValgrindAuditor::do_afterExecute(const std::string& name)
207 {
208  if ( algMatch(name) ) {
210  m_valSvc->callgrindStopInstrumentation();
211  if ( msgLevel() <= MSG::DEBUG )
212  msgStream() << MSG::DEBUG << "Stopping callgrind after execute of " << name
213  << " [event #" << m_eventCounter << "]" << endmsg;
214  }
215  }
216 }
217 
218 
219 /********************************************************************************
220  * Enable callgrind instrumentation
221  */
222 void ValgrindAuditor::do_before(const std::string& name, const std::string& hook)
223 {
224  std::vector< std::pair<NameEvt,NameEvt> >::const_iterator iter;
225 
226  for (iter=m_hooks.begin(); iter!=m_hooks.end(); ++iter) {
227  if ( boost::regex_match(name, iter->first.first) &&
228  iter->first.second == hook ) {
229  m_valSvc->callgrindStartInstrumentation();
230  if ( msgLevel() <= MSG::DEBUG )
231  msgStream() << MSG::DEBUG << "Starting callgrind before " << hook
232  << " of " << name << endmsg;
233  }
234  }
235 }
236 
237 /********************************************************************************
238  * Disable callgrind instrumentation
239  */
240 void ValgrindAuditor::do_after(const std::string& name, const std::string& hook)
241 {
242  std::vector< std::pair<NameEvt,NameEvt> >::const_iterator iter;
243 
244  for (iter=m_hooks.begin(); iter!=m_hooks.end(); ++iter) {
245  if ( boost::regex_match(name, iter->second.first) &&
246  iter->second.second == hook ) {
247  m_valSvc->callgrindStopInstrumentation();
248  if ( msgLevel() <= MSG::DEBUG )
249  msgStream() << MSG::DEBUG << "Stopping callgrind after " << hook
250  << " of " << name << endmsg;
251 
252  if ( m_dumpAfterEachInterval ) {
253  m_valSvc->callgrindDumpStats(msgStream().stream());
254  msgStream() << MSG::INFO << "Creating callgrind profile #" << m_valSvc->profileCount()
255  << " after " << hook << " of " << name << endmsg;
256  }
257  }
258  }
259 }
260 
261 
262 /********************************************************************************
263  * Decodes the intervals
264  */
265 
266 namespace {
267  // Helper to decode name/event pair from string (e.g. MyAlg.initialize)
268  StatusCode decodeNameEvt(const std::string& s, ValgrindAuditor::NameEvt& nameEvt)
269  {
270  // Find last(!) "." delimiter (earlier ones might be part of regexp)
271  string::size_type loc = s.rfind('.');
272  if ( loc==string::npos ) return StatusCode::FAILURE;
273 
274  try {
275  nameEvt.first = boost::regex(s.substr(0,loc));
276  }
277  catch ( const boost::regex_error& ) {
278  return StatusCode::FAILURE;
279  }
280 
281  nameEvt.second = s.substr(loc+1);
282 
283  return StatusCode::SUCCESS;
284  }
285 }
286 
288 {
289  m_hooks.clear();
290  m_hooks.reserve(m_intervals.size());
291 
292  std::vector<string>::const_iterator iter = m_intervals.begin();
293  for (; iter!=m_intervals.end(); ++iter) {
294  const string& spec = *iter;
295  string::size_type loc = spec.find(':');
296 
297  // If there is no delimiter interpret as [a,a]
298  string s1, s2;
299  if (loc==string::npos) s1 = s2 = spec;
300  else { // Extract interval
301  s1 = spec.substr(0,loc);
302  s2 = spec.substr(loc+1);
303  }
304 
305  NameEvt ne1, ne2;
306  if ( s1=="" || s2=="" ||
307  decodeNameEvt(s1,ne1).isFailure() || decodeNameEvt(s2,ne2).isFailure() ) {
308  msgStream() << MSG::ERROR << "Invalid profiling interval [" << spec << "]" << endmsg;
309  return StatusCode::FAILURE;
310  }
311 
312  std::pair<NameEvt,NameEvt> p(ne1,ne2);
313  m_hooks.push_back(p);
314  }
315 
316  return StatusCode::SUCCESS;
317 }
318 
319 /********************************************************************************
320  * Match the algorithm name against all regular expressions
321  */
322 bool ValgrindAuditor::algMatch(const std::string& name)
323 {
324  std::vector<boost::regex>::const_iterator iter;
325  for ( iter=m_algsRegEx.begin(); iter!=m_algsRegEx.end(); ++iter ) {
326  if ( boost::regex_match(name,*iter) ) return true;
327  }
328  return false;
329 }
330 
ValgrindAuditor::decodeIntervals
StatusCode decodeIntervals()
Definition: ValgrindAuditor.cxx:287
ReadCellNoiseFromCoolCompare.s1
s1
Definition: ReadCellNoiseFromCoolCompare.py:378
python.SystemOfUnits.s
int s
Definition: SystemOfUnits.py:131
AthCheckMacros.h
python.TestDriveDummies.properties
dictionary properties
Definition: TestDriveDummies.py:14
ValgrindAuditor::after
virtual void after(StandardEventType evt, const std::string &name, const StatusCode &sc)
Definition: ValgrindAuditor.cxx:175
CaloCondBlobAlgs_fillNoiseFromASCII.spec
spec
Definition: CaloCondBlobAlgs_fillNoiseFromASCII.py:47
ValgrindAuditor::m_algs
std::vector< std::string > m_algs
List of algorithms to profile.
Definition: ValgrindAuditor.h:93
max
constexpr double max()
Definition: ap_fixedTest.cxx:33
ValgrindAuditor::handle
virtual void handle(const Incident &incident)
Incident handler.
Definition: ValgrindAuditor.cxx:146
python.AthDsoLogger.out
out
Definition: AthDsoLogger.py:71
LArG4FSStartPointFilter.evt
evt
Definition: LArG4FSStartPointFilter.py:42
ValgrindAuditor::m_algsRegEx
std::vector< boost::regex > m_algsRegEx
Regular expressions for algorithm name matching.
Definition: ValgrindAuditor.h:108
ValgrindAuditor::m_valSvc
ServiceHandle< IValgrindSvc > m_valSvc
Handle to ValgrindSvc.
Definition: ValgrindAuditor.h:90
ValgrindAuditor::m_ignoreFirstNEvents
unsigned int m_ignoreFirstNEvents
Don't profile on the first N events.
Definition: ValgrindAuditor.h:99
ValgrindAuditor::ValgrindAuditor
ValgrindAuditor(const std::string &name, ISvcLocator *pSvcLocator)
Definition: ValgrindAuditor.cxx:26
AthenaPoolTestWrite.stream
string stream
Definition: AthenaPoolTestWrite.py:12
ValgrindAuditor::m_hooks
std::vector< std::pair< NameEvt, NameEvt > > m_hooks
Internal storage of intervals.
Definition: ValgrindAuditor.h:111
ValgrindAuditor::m_dumpAfterEachInterval
bool m_dumpAfterEachInterval
Dump profile after each interval.
Definition: ValgrindAuditor.h:102
ValgrindAuditor::NameEvt
std::pair< boost::regex, std::string > NameEvt
Typedef for algorithm/event pair, e.g. ("MyAlg","initialize")
Definition: ValgrindAuditor.h:85
PrepareReferenceFile.regex
regex
Definition: PrepareReferenceFile.py:43
ValgrindAuditor::m_eventCounter
unsigned int m_eventCounter
Internal event counter for BeginEvent incident.
Definition: ValgrindAuditor.h:105
LArPulseShapeRunConfig.Execute
Execute
Definition: LArPulseShapeRunConfig.py:62
ValgrindAuditor.h
python.utils.AtlRunQueryDQUtils.p
p
Definition: AtlRunQueryDQUtils.py:210
IValgrindSvc.h
endmsg
#define endmsg
Definition: AnalysisConfig_Ntuple.cxx:63
EL::StatusCode
::StatusCode StatusCode
StatusCode definition for legacy code.
Definition: PhysicsAnalysis/D3PDTools/EventLoop/EventLoop/StatusCode.h:22
extractSporadic.h
list h
Definition: extractSporadic.py:97
ATH_CHECK
#define ATH_CHECK
Definition: AthCheckMacros.h:40
ValgrindAuditor::algMatch
bool algMatch(const std::string &name)
Definition: ValgrindAuditor.cxx:322
ReadFromCoolCompare.os
os
Definition: ReadFromCoolCompare.py:231
ValgrindAuditor::do_after
void do_after(const std::string &name, const std::string &hook)
Definition: ValgrindAuditor.cxx:240
ValgrindAuditor::do_before
void do_before(const std::string &name, const std::string &hook)
Definition: ValgrindAuditor.cxx:222
name
std::string name
Definition: Control/AthContainers/Root/debug.cxx:228
ValgrindAuditor::before
virtual void before(StandardEventType evt, const std::string &name)
Definition: ValgrindAuditor.cxx:165
ValgrindAuditor::m_intervals
std::vector< std::string > m_intervals
List of auditor intervals to profile.
Definition: ValgrindAuditor.h:96
h
re
const boost::regex re(r_e)
DEBUG
#define DEBUG
Definition: page_access.h:11
ReadCellNoiseFromCoolCompare.s2
s2
Definition: ReadCellNoiseFromCoolCompare.py:379
ValgrindAuditor::do_beforeExecute
virtual void do_beforeExecute(const std::string &name)
Start callgrind instrumentation.
Definition: ValgrindAuditor.cxx:189
calibdata.copy
bool copy
Definition: calibdata.py:27
python.Constants.VERBOSE
int VERBOSE
Definition: Control/AthenaCommon/python/Constants.py:14
ValgrindAuditor::initialize
virtual StatusCode initialize()
Definition: ValgrindAuditor.cxx:51
ValgrindAuditor::~ValgrindAuditor
virtual ~ValgrindAuditor()
Definition: ValgrindAuditor.cxx:46
ValgrindAuditor::do_afterExecute
virtual void do_afterExecute(const std::string &name)
Stop callgrind instrumentation.
Definition: ValgrindAuditor.cxx:206
ServiceHandle< IIncidentSvc >