14#include "arcane/utils/ArcanePrecomp.h"
16#include "arcane/utils/String.h"
17#include "arcane/utils/Iostream.h"
18#include "arcane/utils/FatalErrorException.h"
19#include "arcane/utils/Iterator.h"
20#include "arcane/utils/MemoryInfo.h"
21#include "arcane/utils/ITraceMng.h"
22#include "arcane/utils/IStackTraceService.h"
23#include "arcane/utils/PlatformUtils.h"
24#include "arcane/utils/ValueConvert.h"
47#ifdef ARCANE_CHECK_MEMORY_USE_MALLOC_HOOK
60extern "C++" MemoryInfo*
61arcaneGlobalTrueMemoryInfo()
63 static MemoryInfo mem_info;
70#ifdef ARCANE_CHECK_MEMORY_USE_MALLOC_HOOK
71static void*(*old_malloc_hook)(size_t,
const void*);
72static void(*old_free_hook)(
void*,
const void*);
73static void*(*old_realloc_hook)(
void* __ptr,
78static Arcane::Int64 global_nb_malloc = 1;
79static void* my_malloc_hook(
size_t size,
const void* caller);
80static void my_free_hook(
void* ptr,
const void* caller);
81static void* my_realloc_hook(
void* __ptr,
84static void _pushHook()
86 __malloc_hook = old_malloc_hook;
87 __free_hook = old_free_hook;
88 __realloc_hook = old_realloc_hook;
92 __malloc_hook = my_malloc_hook;
93 __free_hook = my_free_hook;
94 __realloc_hook = my_realloc_hook;
97static void* my_malloc_hook(
size_t size,
const void* )
100 void* r = malloc(size);
103 arcaneGlobalTrueMemoryInfo()->addInfo(0,r,size);
104 arcaneGlobalTrueMemoryInfo()->checkMemory(0,size);
108static void my_free_hook(
void* ptr,
const void* )
111 arcaneGlobalTrueMemoryInfo()->removeInfo(0,ptr,
true);
117static void* my_realloc_hook(
void* ptr,
size_t size,
const void* )
123 arcaneGlobalTrueMemoryInfo()->removeInfo(0,ptr,
true);
124 void* r = realloc(ptr,size);
127 arcaneGlobalTrueMemoryInfo()->addInfo(0,r,size);
128 arcaneGlobalTrueMemoryInfo()->checkMemory(0,size);
133static void _initMallocHook()
135 old_malloc_hook = __malloc_hook;
136 __malloc_hook = my_malloc_hook;
137 old_free_hook = __free_hook;
138 __free_hook = my_free_hook;
139 old_realloc_hook = __realloc_hook;
140 __realloc_hook = my_realloc_hook;
143static void _restoreMallocHook()
145 __free_hook = old_free_hook;
146 __malloc_hook = old_malloc_hook;
147 __realloc_hook = old_realloc_hook;
151static void _initMallocHook()
154static void _restoreMallocHook()
157static void _pushHook()
160static void _popHook()
165static bool global_check_memory =
false;
167arcaneInitCheckMemory()
169 String s = platform::getEnvironmentVariable(
"ARCANE_CHECK_MEMORY");
171 global_check_memory =
true;
172 arcaneGlobalMemoryInfo()->beginCollect();
177arcaneExitCheckMemory()
179 if (global_check_memory)
180 arcaneGlobalMemoryInfo()->endCollect();
181 global_check_memory =
false;
191, m_current_allocated(0)
192, m_biggest_allocated(0)
193, m_info_big_alloc(1000000)
194, m_info_biggest_minimal(2000000)
195, m_info_peak_minimal(10000000)
198, m_display_max_alloc(true)
200, m_is_first_collect(true)
201, m_is_stack_trace_active(true)
217setOwner(
const void* owner,
const TraceInfo& ti)
219 MemoryTraceInfoMap::iterator i = m_owner_infos.find(owner);
220 if (i!=m_owner_infos.end()){
229addInfo(
const void* owner,
const void* ptr,Int64 size)
233 MemoryInfoMap::const_iterator i = m_infos.find(ptr);
236 if (i==m_infos.end()){
240 if (size>=m_info_big_alloc && m_is_stack_trace_active){
244 c.setStackTrace(stack_value);
247 m_infos.insert(MemoryInfoMap::value_type(ptr,c));
253 cout <<
"** addInfo() ALREADY IN MAP VALUE=" << ptr <<
" size=" << size <<
'\n';
256 m_current_allocated += size;
264createOwner(
const void* owner,
const TraceInfo& trace_info)
266 MemoryTraceInfoMap::iterator i = m_owner_infos.find(owner);
267 if (i==m_owner_infos.end()){
269 m_owner_infos.insert(MemoryTraceInfoMap::value_type(owner,trace_info));
272 cout <<
"** createOwner() ALREADY IN MAP VALUE=" << owner <<
'\n';
281addInfo(
const void* owner,
const void* ptr,Int64 size,
const void* )
283 addInfo(owner,ptr,size);
290changeOwner(
const void* new_owner,
const void* ptr)
292 MemoryTraceInfoMap::iterator i_owner = m_owner_infos.find(new_owner);
293 if (i_owner==m_owner_infos.end()){
294 cerr <<
"** UNKNOWN NEW OWNER " << new_owner <<
'\n';
295 throw FatalErrorException(
"MemoryInfo::changeOwner() unknown new owner");
298 MemoryInfoMap::iterator i = m_infos.find(ptr);
299 if (i==m_infos.end()){
300 cout <<
"** BAD VALUE=" << ptr <<
'\n';
301 throw FatalErrorException(
"MemoryInfo::changeOwner() pointer not in map");
304 i->second.setOwner(i_owner->first);
313_removeOwner(
const void* owner)
315 MemoryTraceInfoMap::iterator i = m_owner_infos.find(owner);
316 if (i!=m_owner_infos.end()){
318 m_owner_infos.erase(i);
326removeOwner(
const void* owner)
335removeInfo(
const void* owner,
const void* ptr,
bool can_fail)
339 MemoryInfoMap::iterator i = m_infos.find(ptr);
341 if (i==m_infos.end()){
344 cout <<
"MemoryInfo::removeInfo() pointer not in map";
348 MemoryInfoChunk& chunk = i->second;
349 Int64 size = chunk.size();
352 _removeMemory(owner,size);
363 MemoryInfoSorter() : m_size(0), m_alloc_id(-1), m_iteration(0), m_ptr(0), m_owner(0) {}
364 MemoryInfoSorter(Int64 size,Int64 alloc_id,Integer iteration,
const void* ptr,
365 const void* owner,
const String& stack_trace)
366 : m_size(size), m_alloc_id(alloc_id), m_iteration(iteration), m_ptr(ptr)
367 , m_owner(owner), m_stack_trace(stack_trace) {}
378 return m_size > rhs.m_size;
387 void print(std::ostream& o)
const
390 o <<
" name=" << m_trace_info->name()
391 <<
" file=" << m_trace_info->file()
392 <<
" line=" << m_trace_info->line();
410printInfos(std::ostream& ostr)
412 bool is_collecting = global_check_memory;
434_printInfos(std::ostream& ostr)
436 Int64 total_size = 0;
437 ostr <<
"MemoryInfos: " << m_infos.size() <<
'\n';
439 size_t nb_chunk = m_infos.size();
440 std::vector<MemoryInfoSorter> sorted_chunk;
441 sorted_chunk.reserve(nb_chunk);
442 for(
const auto& i : m_infos ){
443 sorted_chunk.push_back(MemoryInfoSorter(i.second.size(),i.second.allocId(),
444 i.second.iteration(),
445 i.first,i.second.owner(),i.second.stackTrace()));
447 std::sort(sorted_chunk.begin(),sorted_chunk.end());
449 for(
const auto& i : sorted_chunk){
450 const void* v = i.m_ptr;
451 const void* owner = i.m_owner;
452 Int64 size = i.m_size;
453 const TraceInfo* ti = 0;
455 MemoryTraceInfoMap::iterator i_owner = m_owner_infos.find(owner);
456 if (i_owner!=m_owner_infos.end()){
457 ti = &i_owner->second;
461 if (size>=m_info_big_alloc){
462 ostr <<
" Remaining: " << v <<
" size=" << size <<
" id=" << i.m_alloc_id
463 <<
" iteration=" << i.m_iteration
464 << TracePrinter(ti) <<
" trace=" << i.m_stack_trace <<
'\n';
467 ostr <<
"Total size=" << total_size;
474printAllocatedMemory(std::ostream& ostr,Integer iteration)
476 ostr <<
" INFO_ALLOCATION: current= " << m_current_allocated
477 <<
" ITERATION= " << iteration
478 <<
" NB_CHUNK=" << m_infos.size()
479 <<
" ID=" << m_alloc_id
481 for( ConstIterT<MemoryInfoMap> i(m_infos); i(); ++i ){
482 const MemoryInfoChunk& mi = i->second;
483 if (mi.iteration()!=iteration)
485 Int64 size = mi.size();
486 if (size>=m_info_big_alloc){
487 ostr <<
" Allocated: " <<
" iteration=" << iteration
488 <<
" size=" << size <<
" id=" << mi.allocId()
489 <<
" trace=" << mi.stackTrace() <<
'\n';
492 for( ConstIterT<MemoryInfoMap> i(m_infos); i(); ++i ){
493 const MemoryInfoChunk& mi = i->second;
494 if (mi.iteration()!=iteration)
496 Int64 size = mi.size();
497 if (size<m_info_big_alloc){
498 ostr <<
" Allocated: " <<
" iteration=" << iteration
499 <<
" size=" << size <<
" id=" << mi.allocId() <<
'\n';
519 if (m_is_first_collect){
520 String s = platform::getEnvironmentVariable(
"ARCANE_CHECK_MEMORY_BLOCK_SIZE");
522 Int64 block_size = 0;
523 bool is_bad = builtInGetValue(block_size,s);
524 if (!is_bad && block_size>2){
525 m_info_big_alloc = block_size;
526 m_info_biggest_minimal = block_size * 2;
527 m_info_peak_minimal = block_size * 10;
530 m_trace->info() <<
" BLOCK SIZE '" << s;
532 m_is_first_collect =
false;
543 _restoreMallocHook();
552 return global_check_memory;
559checkMemory(
const void* owner,Int64 size)
561 if (m_current_allocated>m_max_allocated){
562 m_max_allocated = m_current_allocated;
563 if (m_display_max_alloc && m_max_allocated>m_info_peak_minimal && size>5000 && m_trace && !m_in_display){
565 m_trace->info() <<
"Memory:PEAK_MEM: iteration=" << m_iteration
566 <<
" max allocation reached: max="
567 << m_max_allocated <<
" size=" << size
568 <<
" id=" << m_alloc_id <<
" "
569 << TracePrinter(_getTraceInfo(owner));
570 m_in_display =
false;
573 if (size>m_biggest_allocated){
574 m_biggest_allocated = size;
575 if (m_display_max_alloc && m_biggest_allocated>m_info_biggest_minimal && m_trace && !m_in_display){
577 m_trace->info() <<
"Memory:PEAK_ALLOC: biggest allocation : " << size <<
" "
578 <<
" id=" << m_alloc_id <<
" "
579 << TracePrinter(_getTraceInfo(owner));
580 m_in_display =
false;
583 if (m_info_big_alloc>0 && size>m_info_big_alloc){
584 if (m_display_max_alloc && m_trace && !m_in_display){
587 IStackTraceService* s = platform::getStackTraceService();
589 stack_value= s->stackTrace(2).toString();
592 m_trace->info() <<
"Memory:BIG_ALLOC: iteration=" << m_iteration
593 <<
" big alloc= " << size
594 <<
" id=" << m_alloc_id
595 <<
" current=" << m_current_allocated
597 <<
" stack=" << stack_value;
599 m_in_display =
false;
608_removeMemory(
const void* ,Int64 size)
610 m_current_allocated -= size;
616TraceInfo* MemoryInfo::
617_getTraceInfo(
const void* owner)
619 MemoryTraceInfoMap::iterator i = m_owner_infos.find(owner);
620 if (i==m_owner_infos.end())
643arcaneGlobalMemoryInfo()
645 return arcaneGlobalTrueMemoryInfo();
Informations sur un bloc alloué.
Interface d'un fonctor avec argument mais sans valeur de retour.
virtual void executeFunctor(ArgType arg)=0
Exécute la méthode associé
virtual StackTrace stackTrace(int first_function=0)=0
Chaîne de caractère indiquant la pile d'appel.
Interface du gestionnaire de traces.
const String & toString() const
Chaîne de caractères indiquant la pile d'appel.
Chaîne de caractères unicode.
bool null() const
Retourne true si la chaîne est nulle.
-*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
bool operator<(const Item &item1, const Item &item2)
Compare deux entités.
std::ostream & operator<<(std::ostream &ostr, eItemKind item_kind)
Opérateur de sortie sur un flot.