15 #include "GaudiKernel/INamedInterface.h"
19 #include "GaudiKernel/ServiceHandle.h"
20 #include "GaudiKernel/IInterface.h"
21 #include "GaudiKernel/IHiveWhiteBoard.h"
43 ISvcLocator* pSvcLocator ) :
44 Auditor (
name, pSvcLocator ),
48 m_defaultStacktraceDepth(0)
52 declareProperty(
"MaxStacktracesPerAlg",
m_stmax);
60 if ( current_stage > 1 )
77 ATH_MSG_INFO(
" allocated then freed : " << counter_tc_mtf);
97 std::ifstream
infile(
"/proc/self/status");
108 return StatusCode::SUCCESS;
115 CHECK( wbsvc.retrieve() );
116 if (
dynamic_cast<IHiveWhiteBoard*
> (wbsvc.get()) !=
nullptr) {
117 ATH_MSG_ERROR (
"AthMemoryAuditor requested in MT job --- not thread safe!");
118 return StatusCode::FAILURE;
128 algorithms[
l]=
"'framework'";
143 ATH_MSG_INFO(
"INIT leaks in algorithm " <<
s <<
" will have stacktrace depth of " <<
r );
168 ATH_MSG_WARNING(
"stdcmalloc is currently not well supported, consider using the much faster tcmalloc implementation");
173 return StatusCode::SUCCESS;
178 if ( current_stage > 1 )
182 std::cerr <<
"AthMemoryAuditor : Creating report\n";
183 std::cerr <<
"==================================\n";
185 std::cerr <<
"-------------------------------------------------------------------------------------\n";
186 if(
getenv(
"AtlasBaseDir"))
187 std::cerr <<
"| AtlasBaseDir : " << std::setw(66) <<
getenv(
"AtlasBaseDir") <<
" |\n";
188 if(
getenv(
"AtlasVersion"))
189 std::cerr <<
"| AtlasVersion : " << std::setw(66) <<
getenv(
"AtlasVersion") <<
" |\n";
191 std::cerr <<
"| CMTCONFIG : " << std::setw(66) <<
getenv(
"CMTCONFIG") <<
" |\n";
192 std::cerr <<
"-------------------------------------------------------------------------------------\n";
193 std::cerr <<
" Note: to see line numbers in below stacktrace you might consider running following :\n";
194 std::cerr <<
" atlasAddress2Line --file <logfile> [--alg <algorithm>]\n";
195 std::cerr <<
"-------------------------------------------------------------------------------------\n";
197 std::cerr <<
"Report of summary of leaks\n";
198 std::cerr <<
"--------------------------\n";
201 std::string str0(
"None");
203 std::vector<unsigned long> leaksInStage(10,0);
204 std::vector<unsigned long> leakedMemInStage(10,0);
212 std::vector<allocSet_tc::iterator>
l;
213 std::vector<uintptr_t>
hash;
216 std::map<uint32_t,std::map<uint32_t,info> > accum;
223 unsigned int reportStage(0);
225 size_t size =
it->allocsize;
236 leaksInStage[reportStage]++;
237 leakedMemInStage[reportStage]+=
size;
240 if (
it!=allocset_tc.end())
242 if(
it->allocatedFrom.size()>=2)
243 h=(uintptr_t)
it->allocatedFrom[1];
244 for (
unsigned int j = 2; j <
it->allocatedFrom.size(); j++)
245 if(
it->allocatedFrom[j])
246 h^=(uintptr_t)
it->allocatedFrom[j];
250 accum[
stage][context].l.push_back(
it);
251 accum[
stage][context].hash.push_back(
h);
256 for (
unsigned int reportStage(0); reportStage<8; ++reportStage )
258 for ( std::map<uint32_t,info>::const_iterator
it=accum[reportStage].
begin();
it!=accum[reportStage].end(); ++
it )
259 std::cerr <<
" NOW " <<
it->first <<
" / " <<
it->second.total_size <<
"\n";
263 for (
unsigned int reportStage(0); reportStage<8; ++reportStage )
269 node* nf(s_first.getNext());
270 node*
np(s_first.getNext());
271 node* nn(s_first.getNext());
272 while ( nf != &s_last )
282 # pragma GCC diagnostic push
283 # pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
289 # pragma GCC diagnostic pop
296 if( stage < 1E6 || stage >= 9E7 )
320 leaksInStage[reportStage]++;
321 leakedMemInStage[reportStage]+=
size;
324 b->allocated=(uintptr_t)(
np+
np->getDeltaPayload());
326 if (
it!=allocset_tc.end())
328 if(
it->allocatedFrom.size()>=2)
329 h=(uintptr_t)
it->allocatedFrom[1];
330 for (
unsigned int j = 2; j <
it->allocatedFrom.size(); j++)
331 if(
it->allocatedFrom[j])
332 h^=(uintptr_t)
it->allocatedFrom[j];
344 accum[
stage][context].l.push_back(
it);
345 accum[
stage][context].hash.push_back(
h);
350 std::cerr <<
"Summary\n" ;
351 std::cerr <<
" " << leaksInStage[0] <<
" Reported leak(s) allocated in event loop, leaking " << leakedMemInStage[0] <<
" bytes\n";
352 std::cerr <<
" " << leaksInStage[1] <<
" Reported leak(s) allocated in constructors, leaking " << leakedMemInStage[1] <<
" bytes\n";
353 std::cerr <<
" " << leaksInStage[2] <<
" Reported leak(s) allocated before initialize, leaking " << leakedMemInStage[2] <<
" bytes\n";
354 std::cerr <<
" " << leaksInStage[3] <<
" Reported leak(s) allocated in initialize, leaking " << leakedMemInStage[3] <<
" bytes\n";
355 std::cerr <<
" " << leaksInStage[4] <<
" Reported leak(s) allocated in re-initialize, leaking " << leakedMemInStage[4] <<
" bytes\n";
356 std::cerr <<
" " << leaksInStage[5] <<
" Reported leak(s) allocated in begin-run, leaking " << leakedMemInStage[5] <<
" bytes\n";
357 std::cerr <<
" " << leaksInStage[6] <<
" Reported leak(s) allocated in end-run, leaking " << leakedMemInStage[6] <<
" bytes\n";
358 std::cerr <<
" " << leaksInStage[7] <<
" Reported leak(s) allocated in finalize, leaking " << leakedMemInStage[7] <<
" bytes\n";
360 std::cerr << std::dec <<
"\n";
362 for (
unsigned int reportStage(0); reportStage<8; ++reportStage )
366 case 0: std::cerr <<
"Reporting leaks allocated in event loop\n";
break;
367 case 1: std::cerr <<
"Reporting leaks allocated in constructors\n";
break;
368 case 2: std::cerr <<
"Reporting leaks allocated before initialize\n";
break;
369 case 3: std::cerr <<
"Reporting leaks allocated in initialize\n";
break;
370 case 4: std::cerr <<
"Reporting leaks allocated in re-initialize\n";
break;
371 case 5: std::cerr <<
"Reporting leaks allocated in begin-run\n";
break;
372 case 6: std::cerr <<
"Reporting leaks allocated in end-run\n";
break;
373 case 7: std::cerr <<
"Reporting leaks allocated in finalize\n";
break;
376 std::map<uint32_t,info> leaks;
378 for(std::map<
uint32_t,std::map<uint32_t,info> >::const_iterator outer_iter=accum.begin(); outer_iter!=accum.end(); ++outer_iter)
383 if( stage < 1E6 || stage >= 9E7 )
408 for(std::map<uint32_t,info>::const_iterator inner_iter = outer_iter->second.begin(); inner_iter!=outer_iter->second.end(); ++inner_iter)
410 leaks[inner_iter->first].total_size+=inner_iter->second.total_size;
411 leaks[inner_iter->first].l.insert(leaks[inner_iter->first].l.end(), inner_iter->second.l.begin(), inner_iter->second.l.end());
412 leaks[inner_iter->first].hash.insert(leaks[inner_iter->first].hash.end(), inner_iter->second.hash.begin(), inner_iter->second.hash.end());
417 while (! leaks.empty())
419 auto imax=leaks.begin();
420 for(
auto iter=leaks.begin(); iter!=leaks.end(); ++iter)
421 if(
imax->second.total_size < iter->second.total_size)
424 std::map<uint32_t, std::string>::const_iterator ait=algorithms.find(ai);
425 if ( ait != algorithms.end() )
429 std::cerr <<
" Accumulated Leak(s) in algorithm " <<
str <<
" of total size " <<
imax->second.total_size <<
" bytes\n";
431 auto fit=arrayAlgIndex.find(
str);
432 if (
fit == arrayAlgIndex.end() )
434 std::cerr <<
"something is wrong \n";
439 stacktraceDepth=
fit->second.stacktrace;
441 if(stacktraceDepth > 0 )
443 std::vector<info> thisAlg;
447 for(
unsigned int i_tr = 0; i_tr <
imax->second.l.size(); ++i_tr )
451 size_t size =
imax->second.l[i_tr]->allocsize;
455 leakSum.total_size=
size;
456 leakSum.l.push_back(
imax->second.l[i_tr]);
457 leakSum.hash.push_back(
stage);
464 b->allocated=(uintptr_t)
imax->second.l[i_tr]->allocated;
466 if (
it!=allocset_tc.end())
469 unsigned int i_tr2 = i_tr+1;
470 while ( i_tr2 < imax->
second.l.size() )
472 if (
imax->second.hash[i_tr] ==
imax->second.hash[i_tr2] )
474 size =
imax->second.l[i_tr2]->allocsize;
482 if (it2!=allocset_tc.end())
485 for (
unsigned int j = 0; j <
std::min(
it->allocatedFrom.size(),it2->allocatedFrom.size()); j++)
486 if(
same &&
it->allocatedFrom[j] && it2->allocatedFrom[j] )
487 if(
it->allocatedFrom[j] != it2->allocatedFrom[j] )
494 leakSum.total_size+=
size;
496 leakSum.l.push_back(
imax->second.l[i_tr2]);
497 leakSum.hash.push_back(
stage);
500 imax->second.l[i_tr2]->curstage=0;
509 thisAlg.push_back(leakSum);
518 while(thisAlg.size())
520 auto itmax = thisAlg.end();
527 itmax = thisAlg.begin();
528 for(
auto iter=thisAlg.begin(); iter!=thisAlg.end(); ++iter)
529 if(itmax->total_size < iter->total_size)
532 stage = itmax->hash[0];
533 std::multimap<int,int> here;
535 std::cerr <<
" " << itmax->l.size() <<
" leak(s) in algorithm " <<
str <<
" allocated in "
537 if(itmax->l.size()>1)
539 for(
auto i = itmax->l.begin();
i != itmax->l.end(); ++
i )
540 here.insert(std::pair<int, int>((*i)->allocsize, 1));
543 auto it = here.end(); --
it;
545 while( ! here.empty() )
548 if( here.count(
it->first) > 1 )
549 std::cerr << here.count(
it->first) <<
"x";
550 std::cerr <<
it->first;
552 here.erase(here.lower_bound(
it->first),here.end());
554 if ( ! here.empty() ) --
it;
566 for (
unsigned int j = 1; j <
it->allocatedFrom.size() ; j++)
568 if(
it->allocatedFrom[j])
572 ptrdiff_t relative_address(0);
573 const char *libname =
"N/A";
574 if (dladdr (
it->allocatedFrom[j], &
info) &&
info.dli_fname &&
info.dli_fname[0])
576 libname =
info.dli_fname;
578 uintptr_t
p1=(uintptr_t)
it->allocatedFrom[j];
579 uintptr_t
p2=(uintptr_t)
info.dli_fbase;
581 if (strstr (
info.dli_fname,
".so") == 0)
582 relative_address =
p1;
584 fprintf(
stderr,
" %s D[%p]\n",libname,(
void*)relative_address);
591 mleaks+=itmax->total_size;
596 thisAlg.erase(itmax);
599 std::cerr <<
" further " << nleaks <<
" leak(s) in algorithm " <<
str <<
" allocated in "
616 std::string
str(
"N/A");
618 if(
s >= 1E6 &&
s < 9E7 )
625 str=
"before initialize";
647 context=(uintptr_t)(&(
comp->name()));
650 auto fit=arrayAlgIndex.find(
comp->name());
651 if (
fit == arrayAlgIndex.end() )
655 collectStacktraces=
false;
660 curIndex=
fit->second.index;
661 stacktraceDepth=
fit->second.stacktrace;
663 algorithms[curIndex]=
comp->name();
668 else if (
evt==IAuditor::ReInitialize) {
670 collectStacktraces=
bool(stacktraceDepth);
673 if(current_stage<1E6)
675 if (context && ( contextFirst == context ) )
677 if (context && ( contextFirst == 0 ) )
678 contextFirst = context;
679 collectStacktraces=
bool(stacktraceDepth);
681 else if (
evt==IAuditor::Finalize) {
683 collectStacktraces=
bool(stacktraceDepth);