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
61arcaneGlobalTrueMemoryInfo()
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 void* my_malloc_hook(
size_t size,
const void* caller);
79static void my_free_hook(
void* ptr,
const void* caller);
80static void* my_realloc_hook(
void* __ptr,
83static void _pushHook()
85 __malloc_hook = old_malloc_hook;
86 __free_hook = old_free_hook;
87 __realloc_hook = old_realloc_hook;
91 __malloc_hook = my_malloc_hook;
92 __free_hook = my_free_hook;
93 __realloc_hook = my_realloc_hook;
96static void* my_malloc_hook(
size_t size,
const void* )
99 void* r = malloc(size);
102 arcaneGlobalTrueMemoryInfo()->addInfo(0, r, size);
103 arcaneGlobalTrueMemoryInfo()->checkMemory(0, size);
107static void my_free_hook(
void* ptr,
const void* )
110 arcaneGlobalTrueMemoryInfo()->removeInfo(0, ptr,
true);
116static void* my_realloc_hook(
void* ptr,
size_t size,
const void* )
122 arcaneGlobalTrueMemoryInfo()->removeInfo(0, ptr,
true);
123 void* r = realloc(ptr, size);
126 arcaneGlobalTrueMemoryInfo()->addInfo(0, r, size);
127 arcaneGlobalTrueMemoryInfo()->checkMemory(0, size);
132static void _initMallocHook()
134 old_malloc_hook = __malloc_hook;
135 __malloc_hook = my_malloc_hook;
136 old_free_hook = __free_hook;
137 __free_hook = my_free_hook;
138 old_realloc_hook = __realloc_hook;
139 __realloc_hook = my_realloc_hook;
142static void _restoreMallocHook()
144 __free_hook = old_free_hook;
145 __malloc_hook = old_malloc_hook;
146 __realloc_hook = old_realloc_hook;
150static void _initMallocHook()
153static void _restoreMallocHook()
156static void _pushHook()
159static void _popHook()
164static bool global_check_memory =
false;
166arcaneInitCheckMemory()
170 global_check_memory =
true;
171 arcaneGlobalMemoryInfo()->beginCollect();
176arcaneExitCheckMemory()
178 if (global_check_memory)
179 arcaneGlobalMemoryInfo()->endCollect();
180 global_check_memory =
false;
190, m_current_allocated(0)
191, m_biggest_allocated(0)
192, m_info_big_alloc(1000000)
193, m_info_biggest_minimal(2000000)
194, m_info_peak_minimal(10000000)
197, m_display_max_alloc(true)
199, m_is_first_collect(true)
200, m_is_stack_trace_active(true)
216setOwner(
const void* owner,
const TraceInfo& ti)
218 MemoryTraceInfoMap::iterator i = m_owner_infos.find(owner);
219 if (i != m_owner_infos.end()) {
228addInfo(
const void* owner,
const void* ptr,
Int64 size)
232 MemoryInfoMap::const_iterator i = m_infos.find(ptr);
235 if (i == m_infos.end()) {
239 if (size >= m_info_big_alloc && m_is_stack_trace_active) {
243 c.setStackTrace(stack_value);
246 m_infos.insert(MemoryInfoMap::value_type(ptr, c));
252 cout <<
"** addInfo() ALREADY IN MAP VALUE=" << ptr <<
" size=" << size <<
'\n';
255 m_current_allocated += size;
263createOwner(
const void* owner,
const TraceInfo& trace_info)
265 MemoryTraceInfoMap::iterator i = m_owner_infos.find(owner);
266 if (i == m_owner_infos.end()) {
268 m_owner_infos.insert(MemoryTraceInfoMap::value_type(owner, trace_info));
271 cout <<
"** createOwner() ALREADY IN MAP VALUE=" << owner <<
'\n';
280addInfo(
const void* owner,
const void* ptr,
Int64 size,
const void* )
282 addInfo(owner, ptr, size);
289changeOwner(
const void* new_owner,
const void* ptr)
291 MemoryTraceInfoMap::iterator i_owner = m_owner_infos.find(new_owner);
292 if (i_owner == m_owner_infos.end()) {
293 cerr <<
"** UNKNOWN NEW OWNER " << new_owner <<
'\n';
294 throw FatalErrorException(
"MemoryInfo::changeOwner() unknown new owner");
297 MemoryInfoMap::iterator i = m_infos.find(ptr);
298 if (i == m_infos.end()) {
299 cout <<
"** BAD VALUE=" << ptr <<
'\n';
300 throw FatalErrorException(
"MemoryInfo::changeOwner() pointer not in map");
303 i->second.setOwner(i_owner->first);
312_removeOwner(
const void* owner)
314 MemoryTraceInfoMap::iterator i = m_owner_infos.find(owner);
315 if (i != m_owner_infos.end()) {
317 m_owner_infos.erase(i);
325removeOwner(
const void* owner)
334removeInfo(
const void* owner,
const void* ptr,
bool can_fail)
338 MemoryInfoMap::iterator i = m_infos.find(ptr);
340 if (i == m_infos.end()) {
343 cout <<
"MemoryInfo::removeInfo() pointer not in map";
347 MemoryInfoChunk& chunk = i->second;
348 Int64 size = chunk.size();
351 _removeMemory(owner, size);
371 const void* owner,
const String& stack_trace)
373 , m_alloc_id(alloc_id)
374 , m_iteration(iteration)
377 , m_stack_trace(stack_trace)
391 bool operator<(
const MemoryInfoSorter& rhs)
const
393 return m_size > rhs.m_size;
404 void print(std::ostream& o)
const
407 o <<
" name=" << m_trace_info->name()
408 <<
" file=" << m_trace_info->file()
409 <<
" line=" << m_trace_info->line();
429printInfos(std::ostream& ostr)
431 bool is_collecting = global_check_memory;
453_printInfos(std::ostream& ostr)
455 Int64 total_size = 0;
456 ostr <<
"MemoryInfos: " << m_infos.size() <<
'\n';
458 size_t nb_chunk = m_infos.size();
459 std::vector<MemoryInfoSorter> sorted_chunk;
460 sorted_chunk.reserve(nb_chunk);
461 for (
const auto& i : m_infos) {
462 sorted_chunk.push_back(MemoryInfoSorter(i.second.size(), i.second.allocId(),
463 i.second.iteration(),
464 i.first, i.second.owner(), i.second.stackTrace()));
466 std::sort(sorted_chunk.begin(), sorted_chunk.end());
468 for (
const auto& i : sorted_chunk) {
469 const void* v = i.m_ptr;
470 const void* owner = i.m_owner;
471 Int64 size = i.m_size;
472 const TraceInfo* ti = 0;
474 MemoryTraceInfoMap::iterator i_owner = m_owner_infos.find(owner);
475 if (i_owner != m_owner_infos.end()) {
476 ti = &i_owner->second;
480 if (size >= m_info_big_alloc) {
481 ostr <<
" Remaining: " << v <<
" size=" << size <<
" id=" << i.m_alloc_id
482 <<
" iteration=" << i.m_iteration
483 << TracePrinter(ti) <<
" trace=" << i.m_stack_trace <<
'\n';
486 ostr <<
"Total size=" << total_size;
493printAllocatedMemory(std::ostream& ostr, Integer iteration)
495 ostr <<
" INFO_ALLOCATION: current= " << m_current_allocated
496 <<
" ITERATION= " << iteration
497 <<
" NB_CHUNK=" << m_infos.size()
498 <<
" ID=" << m_alloc_id
500 for (ConstIterT<MemoryInfoMap> i(m_infos); i(); ++i) {
501 const MemoryInfoChunk& mi = i->second;
502 if (mi.iteration() != iteration)
504 Int64 size = mi.size();
505 if (size >= m_info_big_alloc) {
506 ostr <<
" Allocated: " <<
" iteration=" << iteration
507 <<
" size=" << size <<
" id=" << mi.allocId()
508 <<
" trace=" << mi.stackTrace() <<
'\n';
511 for (ConstIterT<MemoryInfoMap> i(m_infos); i(); ++i) {
512 const MemoryInfoChunk& mi = i->second;
513 if (mi.iteration() != iteration)
515 Int64 size = mi.size();
516 if (size < m_info_big_alloc) {
517 ostr <<
" Allocated: " <<
" iteration=" << iteration
518 <<
" size=" << size <<
" id=" << mi.allocId() <<
'\n';
538 if (m_is_first_collect) {
541 Int64 block_size = 0;
542 bool is_bad = builtInGetValue(block_size, s);
543 if (!is_bad && block_size > 2) {
544 m_info_big_alloc = block_size;
545 m_info_biggest_minimal = block_size * 2;
546 m_info_peak_minimal = block_size * 10;
549 m_trace->info() <<
" BLOCK SIZE '" << s;
551 m_is_first_collect =
false;
562 _restoreMallocHook();
571 return global_check_memory;
578checkMemory(
const void* owner, Int64 size)
580 if (m_current_allocated > m_max_allocated) {
581 m_max_allocated = m_current_allocated;
582 if (m_display_max_alloc && m_max_allocated > m_info_peak_minimal && size > 5000 && m_trace && !m_in_display) {
584 m_trace->info() <<
"Memory:PEAK_MEM: iteration=" << m_iteration
585 <<
" max allocation reached: max="
586 << m_max_allocated <<
" size=" << size
587 <<
" id=" << m_alloc_id <<
" "
588 << TracePrinter(_getTraceInfo(owner));
589 m_in_display =
false;
592 if (size > m_biggest_allocated) {
593 m_biggest_allocated = size;
594 if (m_display_max_alloc && m_biggest_allocated > m_info_biggest_minimal && m_trace && !m_in_display) {
596 m_trace->info() <<
"Memory:PEAK_ALLOC: biggest allocation : " << size <<
" "
597 <<
" id=" << m_alloc_id <<
" "
598 << TracePrinter(_getTraceInfo(owner));
599 m_in_display =
false;
602 if (m_info_big_alloc > 0 && size > m_info_big_alloc) {
603 if (m_display_max_alloc && m_trace && !m_in_display) {
606 IStackTraceService* s = platform::getStackTraceService();
608 stack_value = s->stackTrace(2).toString();
611 m_trace->info() <<
"Memory:BIG_ALLOC: iteration=" << m_iteration
612 <<
" big alloc= " << size
613 <<
" id=" << m_alloc_id
614 <<
" current=" << m_current_allocated
616 <<
" stack=" << stack_value;
618 m_in_display =
false;
627_removeMemory(
const void* , Int64 size)
629 m_current_allocated -= size;
635TraceInfo* MemoryInfo::
636_getTraceInfo(
const void* owner)
638 MemoryTraceInfoMap::iterator i = m_owner_infos.find(owner);
639 if (i == m_owner_infos.end())
654 functor->executeFunctor(mic);
662arcaneGlobalMemoryInfo()
664 return arcaneGlobalTrueMemoryInfo();
Interface of a functor with an argument but without a return value.
virtual StackTrace stackTrace(int first_function=0)=0
Character string indicating the call stack.
Information about an allocated chunk.
const String & toString() const
String indicating the call stack.
Unicode character string.
bool null() const
Returns true if the string is null.
-- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature --
std::int64_t Int64
Signed integer type of 64 bits.
Int32 Integer
Type representing an integer.
std::ostream & operator<<(std::ostream &ostr, eItemKind item_kind)
Output operator for a stream.