14#include "arccore/common/internal/MemoryPool.h"
16#include "arccore/base/FatalErrorException.h"
17#include "arccore/base/PlatformUtils.h"
18#include "arccore/base/Convert.h"
20#include "arccore/common/Array.h"
22#include <unordered_map>
44 using MapType = std::unordered_map<void*, size_t>;
46 using MapIterator = MapType::iterator;
50 explicit AllocatedMap(
const String& name)
56 void removePointer(
void* ptr,
size_t size)
58 std::unique_lock<std::mutex> lg(m_mutex);
59 auto x = m_allocated_memory_map.find(ptr);
60 if (x == m_allocated_memory_map.end()) {
62 String str = String::format(
"MemoryPool '{0}': pointer {1} is not in the allocated map", m_name, ptr);
64 std::cerr <<
"ERROR: " << str <<
"\n";
68 size_t allocated_size = x->second;
69 if (size != allocated_size) {
71 String str = String::format(
"MemoryPool '{0}': Incoherent size saved_size={1} arg_size={2}",
72 m_name, allocated_size, size);
74 std::cerr <<
"ERROR: " << str <<
"\n";
77 m_allocated_memory_map.erase(x);
80 void addPointer(
void* ptr,
size_t size)
82 std::unique_lock<std::mutex> lg(m_mutex);
83 auto x = m_allocated_memory_map.find(ptr);
85 "MemoryPool '{0}': pointer {1} (for size={2}) is already in the allocated map (with size={3})",
86 m_name, ptr, size, x->second);
87 m_allocated_memory_map.insert(std::make_pair(ptr, size));
92 std::unique_lock<std::mutex> lg(m_mutex);
93 return m_allocated_memory_map.size();
96 bool isThrowOnError()
const {
return m_is_throw_on_error; }
97 void setIsThrowOnError(
bool v) { m_is_throw_on_error = v; }
98 Int32 nbError()
const {
return m_nb_error; }
102 MapType m_allocated_memory_map;
104 std::atomic<Int32> m_nb_error = 0;
105 bool m_is_throw_on_error =
false;
106 mutable std::mutex m_mutex;
116 using MapType = std::unordered_multimap<size_t, void*>;
120 explicit FreedMap(
const String& name)
134 std::unique_lock<std::mutex> lg(m_mutex);
136 auto x = m_free_memory_map.find(size);
137 if (x != m_free_memory_map.end()) {
139 m_free_memory_map.erase(x);
144 void addPointer(
void* ptr,
size_t size)
146 std::unique_lock<std::mutex> lg(m_mutex);
147 m_free_memory_map.insert(std::make_pair(size, ptr));
152 std::unique_lock<std::mutex> lg(m_mutex);
153 return m_free_memory_map.size();
156 void dump(std::ostream& ostr)
158 std::map<size_t, Int32> nb_alloc_per_size;
160 std::unique_lock<std::mutex> lg(m_mutex);
161 for (
const auto& [key, value] : m_free_memory_map) {
162 auto x = nb_alloc_per_size.find(key);
163 if (x == nb_alloc_per_size.end())
164 nb_alloc_per_size.insert(std::make_pair(key, 1));
169 ostr <<
"FreedMap '" << m_name <<
"\n";
170 for (
const auto& [key, value] : nb_alloc_per_size)
171 ostr <<
"Map size=" << key <<
" nb_allocated=" << value <<
" page_modulo=" << (key % 4096) <<
"\n";
177 std::unique_lock<std::mutex> lg(m_mutex);
178 values.reserve(m_free_memory_map.size());
179 for (
const auto& [size, ptr] : m_free_memory_map)
180 values.add(std::make_pair(ptr, size));
181 m_free_memory_map.clear();
186 MapType m_free_memory_map;
188 mutable std::mutex m_mutex;
193 explicit Impl(IMemoryPoolAllocator* allocator,
const String& name)
194 : m_allocator(allocator)
195 , m_allocated_map(name)
200 bool throw_on_error = (v.value() != 0);
201 m_allocated_map.setIsThrowOnError(throw_on_error);
214 void* allocateMemory(
size_t size);
215 void freeMemory(
void* ptr,
size_t size);
216 void dumpStats(std::ostream& ostr);
217 void dumpFreeMap(std::ostream& ostr);
218 void setMaxCachedBlockSize(Int32 v);
219 void freeCachedMemory();
223 IMemoryPoolAllocator* m_allocator =
nullptr;
225 AllocatedMap m_allocated_map;
228 std::atomic<Int64> m_total_allocated = 0;
229 std::atomic<Int64> m_total_free = 0;
230 std::atomic<Int32> m_nb_cached = 0;
231 std::atomic<Int32> m_nb_no_cached = 0;
232 size_t m_max_memory_size_to_pool = 1024 * 64 * 4 * 4;
237 void _freeMemory(
void* ptr);
238 void _addAllocated(
void* ptr,
size_t size);
244void* MemoryPool::Impl::
245allocateMemory(
size_t size)
247 if (m_max_memory_size_to_pool != 0 && size > m_max_memory_size_to_pool) {
249 return m_allocator->allocateMemory(size);
254 m_total_free -= size;
258 ptr = m_allocator->allocateMemory(size);
260 _addAllocated(ptr, size);
267void MemoryPool::Impl::
268freeMemory(
void* ptr,
size_t size)
270 if (m_max_memory_size_to_pool != 0 && size > m_max_memory_size_to_pool)
271 return m_allocator->freeMemory(ptr, size);
273 m_allocated_map.removePointer(ptr, size);
275 m_free_map.addPointer(ptr, size);
276 m_total_allocated -= size;
277 m_total_free += size;
283void MemoryPool::Impl::
284_addAllocated(
void* ptr,
size_t size)
286 m_allocated_map.addPointer(ptr, size);
287 m_total_allocated += size;
293void MemoryPool::Impl::
294dumpStats(std::ostream& ostr)
296 ostr <<
"Stats '" << m_name <<
"' max_block=" << m_max_memory_size_to_pool
297 <<
" TotalAllocated=" << m_total_allocated
298 <<
" TotalFree=" << m_total_free
299 <<
" nb_allocated=" << m_allocated_map.size()
300 <<
" nb_free=" << m_free_map.size()
301 <<
" nb_cached=" << m_nb_cached
302 <<
" nb_no_cached=" << m_nb_no_cached
303 <<
" nb_error=" << m_allocated_map.nbError()
310void MemoryPool::Impl::
311dumpFreeMap(std::ostream& ostr)
313 m_free_map.dump(ostr);
319void MemoryPool::Impl::
320setMaxCachedBlockSize(
Int32 v)
322 if (m_allocated_map.size() != 0 || m_free_map.size() != 0)
323 ARCCORE_FATAL(
"Can not change maximum cached block size on non empty pool");
326 m_max_memory_size_to_pool = v;
332void MemoryPool::Impl::
335 UniqueArray<std::pair<void*, size_t>> values_to_free;
336 m_free_map.fillFreeMapAndClear(values_to_free);
337 for (
const auto& v : values_to_free) {
338 m_allocator->freeMemory(v.first, v.second);
349MemoryPool(IMemoryPoolAllocator* allocator,
const String& name)
350: m_p(std::make_unique<
Impl>(allocator, name))
365void* MemoryPool::allocateMemory(
Int64 size)
367 return m_p->allocateMemory(size);
369void MemoryPool::freeMemory(
void* ptr,
Int64 size)
371 m_p->freeMemory(ptr, size);
373void MemoryPool::dumpStats(std::ostream& ostr)
375 m_p->dumpStats(ostr);
378dumpFreeMap(std::ostream& ostr)
380 m_p->dumpFreeMap(ostr);
382String MemoryPool::name()
const
387setMaxCachedBlockSize(
Int32 v)
389 m_p->setMaxCachedBlockSize(v);
394 m_p->freeCachedMemory();
397totalAllocated()
const
399 return m_p->m_total_allocated;
404 return m_p->m_total_free;
#define ARCCORE_FATAL(...)
Macro envoyant une exception FatalErrorException.
#define ARCCORE_FATAL_IF(cond,...)
Macro envoyant une exception FatalErrorException si cond est vrai.
Classe de base des vecteurs 1D de données.
Classe template pour convertir un type.
Tableau associatif des emplacements mémoire libres par taille.
void fillFreeMapAndClear(Array< std::pair< void *, size_t > > &values)
Remplit values avec les valeurs de m_free_memory_map et vide cette dernière.
void * getPointer(size_t size)
Récupère un pointeur pour une taille size.
FreedMap m_free_map
Liste des allocations libres dans le cache.
Chaîne de caractères unicode.
std::int64_t Int64
Type entier signé sur 64 bits.
std::int32_t Int32
Type entier signé sur 32 bits.