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)
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){
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;
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) {}
366 : m_size(size), m_alloc_id(
alloc_id), m_iteration(iteration), m_ptr(
ptr)
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)
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())
635 functor->executeFunctor(
mic);
643arcaneGlobalMemoryInfo()
645 return arcaneGlobalTrueMemoryInfo();
Interface d'un collecteur d'informations sur l'usage mémoire.
Lecteur des fichiers de maillage via la bibliothèque LIMA.
Informations sur un bloc alloué.
Interface d'un service de trace des appels de fonctions.
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.
TraceMessage info() const
Flot pour un message d'information.
-*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-