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>
43 using MapType = std::unordered_map<void*, size_t>;
45 using MapIterator = MapType::iterator;
49 explicit AllocatedMap(
const String& name)
55 void removePointer(
void* ptr,
size_t size)
57 std::unique_lock<std::mutex> lg(m_mutex);
58 auto x = m_allocated_memory_map.find(ptr);
59 if (x == m_allocated_memory_map.end()) {
61 String str = String::format(
"MemoryPool '{0}': pointer {1} is not in the allocated map", m_name, ptr);
62 ARCCORE_FATAL_IF(m_is_throw_on_error, str);
63 std::cerr <<
"ERROR: " << str <<
"\n";
67 size_t allocated_size = x->second;
68 if (size != allocated_size) {
70 String str = String::format(
"MemoryPool '{0}': Incoherent size saved_size={1} arg_size={2}",
71 m_name, allocated_size, size);
72 ARCCORE_FATAL_IF(m_is_throw_on_error, str);
73 std::cerr <<
"ERROR: " << str <<
"\n";
76 m_allocated_memory_map.erase(x);
79 void addPointer(
void* ptr,
size_t size)
81 std::unique_lock<std::mutex> lg(m_mutex);
82 auto x = m_allocated_memory_map.find(ptr);
83 ARCCORE_FATAL_IF((x != m_allocated_memory_map.end()),
84 "MemoryPool '{0}': pointer {1} (for size={2}) is already in the allocated map (with size={3})",
85 m_name, ptr, size, x->second);
86 m_allocated_memory_map.insert(std::make_pair(ptr, size));
91 std::unique_lock<std::mutex> lg(m_mutex);
92 return m_allocated_memory_map.size();
95 bool isThrowOnError()
const {
return m_is_throw_on_error; }
96 void setIsThrowOnError(
bool v) { m_is_throw_on_error = v; }
97 Int32 nbError()
const {
return m_nb_error; }
101 MapType m_allocated_memory_map;
103 std::atomic<Int32> m_nb_error = 0;
104 bool m_is_throw_on_error =
false;
105 mutable std::mutex m_mutex;
115 using MapType = std::unordered_multimap<size_t, void*>;
119 explicit FreedMap(
const String& name)
133 std::unique_lock<std::mutex> lg(m_mutex);
135 auto x = m_free_memory_map.find(size);
136 if (x != m_free_memory_map.end()) {
138 m_free_memory_map.erase(x);
143 void addPointer(
void* ptr,
size_t size)
145 std::unique_lock<std::mutex> lg(m_mutex);
146 m_free_memory_map.insert(std::make_pair(size, ptr));
151 std::unique_lock<std::mutex> lg(m_mutex);
152 return m_free_memory_map.size();
155 void dump(std::ostream& ostr)
157 std::map<size_t, Int32> nb_alloc_per_size;
159 std::unique_lock<std::mutex> lg(m_mutex);
160 for (
const auto& [key, value] : m_free_memory_map) {
161 auto x = nb_alloc_per_size.find(key);
162 if (x == nb_alloc_per_size.end())
163 nb_alloc_per_size.insert(std::make_pair(key, 1));
168 ostr <<
"FreedMap '" << m_name <<
"\n";
169 for (
const auto& [key, value] : nb_alloc_per_size)
170 ostr <<
"Map size=" << key <<
" nb_allocated=" << value <<
" page_modulo=" << (key % 4096) <<
"\n";
176 std::unique_lock<std::mutex> lg(m_mutex);
177 values.reserve(m_free_memory_map.size());
178 for (
const auto& [size, ptr] : m_free_memory_map)
179 values.add(std::make_pair(ptr, size));
180 m_free_memory_map.clear();
185 MapType m_free_memory_map;
187 mutable std::mutex m_mutex;
192 explicit Impl(IMemoryPoolAllocator* allocator,
const String& name)
193 : m_allocator(allocator)
194 , m_allocated_map(name)
199 bool throw_on_error = (v.value() != 0);
200 m_allocated_map.setIsThrowOnError(throw_on_error);
213 void* allocateMemory(
size_t size);
214 void freeMemory(
void* ptr,
size_t size);
215 void dumpStats(std::ostream& ostr);
216 void dumpFreeMap(std::ostream& ostr);
217 void setMaxCachedBlockSize(
size_t v);
218 void freeCachedMemory();
222 IMemoryPoolAllocator* m_allocator =
nullptr;
224 AllocatedMap m_allocated_map;
227 std::atomic<size_t> m_total_allocated = 0;
228 std::atomic<size_t> m_total_free = 0;
229 std::atomic<Int32> m_nb_cached = 0;
230 std::atomic<Int32> m_nb_no_cached = 0;
231 size_t m_max_memory_size_to_pool = 1024 * 64 * 4 * 4;
236 void _freeMemory(
void* ptr);
237 void _addAllocated(
void* ptr,
size_t size);
243void* MemoryPool::Impl::
244allocateMemory(
size_t size)
246 if (m_max_memory_size_to_pool != 0 && size > m_max_memory_size_to_pool) {
248 return m_allocator->allocateMemory(size);
253 m_total_free -= size;
257 ptr = m_allocator->allocateMemory(size);
259 _addAllocated(ptr, size);
266void MemoryPool::Impl::
267freeMemory(
void* ptr,
size_t size)
269 if (m_max_memory_size_to_pool != 0 && size > m_max_memory_size_to_pool)
270 return m_allocator->freeMemory(ptr, size);
272 m_allocated_map.removePointer(ptr, size);
274 m_free_map.addPointer(ptr, size);
275 m_total_allocated -= size;
276 m_total_free += size;
282void MemoryPool::Impl::
283_addAllocated(
void* ptr,
size_t size)
285 m_allocated_map.addPointer(ptr, size);
286 m_total_allocated += size;
292void MemoryPool::Impl::
293dumpStats(std::ostream& ostr)
295 ostr <<
"Stats '" << m_name <<
"' max_block=" << m_max_memory_size_to_pool
296 <<
" TotalAllocated=" << m_total_allocated
297 <<
" TotalFree=" << m_total_free
298 <<
" nb_allocated=" << m_allocated_map.size()
299 <<
" nb_free=" << m_free_map.size()
300 <<
" nb_cached=" << m_nb_cached
301 <<
" nb_no_cached=" << m_nb_no_cached
302 <<
" nb_error=" << m_allocated_map.nbError()
309void MemoryPool::Impl::
310dumpFreeMap(std::ostream& ostr)
312 m_free_map.dump(ostr);
318void MemoryPool::Impl::
319setMaxCachedBlockSize(
size_t v)
321 if (m_allocated_map.size() != 0 || m_free_map.size() != 0)
322 ARCCORE_FATAL(
"Can not change maximum cached block size on non empty pool");
323 m_max_memory_size_to_pool = v;
329void MemoryPool::Impl::
332 UniqueArray<std::pair<void*, size_t>> values_to_free;
333 m_free_map.fillFreeMapAndClear(values_to_free);
334 for (
const auto& v : values_to_free) {
335 m_allocator->freeMemory(v.first, v.second);
346MemoryPool(IMemoryPoolAllocator* allocator,
const String& name)
347: m_p(std::make_shared<
Impl>(allocator, name))
362void* MemoryPool::allocateMemory(
size_t size)
364 return m_p->allocateMemory(size);
366void MemoryPool::freeMemory(
void* ptr,
size_t size)
368 m_p->freeMemory(ptr, size);
370void MemoryPool::dumpStats(std::ostream& ostr)
372 m_p->dumpStats(ostr);
375dumpFreeMap(std::ostream& ostr)
377 m_p->dumpFreeMap(ostr);
379String MemoryPool::name()
const
384setMaxCachedBlockSize(
size_t v)
386 m_p->setMaxCachedBlockSize(v);
391 m_p->freeCachedMemory();
Classe de base des vecteurs 1D de données.
Classe template pour convertir un type.
Chaîne de caractères unicode.
Tableau associatif des emplacements mémoire libres par taille.
void * getPointer(size_t size)
Récupère un pointeur pour une taille size.
void fillFreeMapAndClear(Array< std::pair< void *, size_t > > &values)
Remplit values avec les valeurs de m_free_memory_map et vide cette dernière.
FreedMap m_free_map
Liste des allocations libres dans le cache.
std::int32_t Int32
Type entier signé sur 32 bits.