14#include "arcane/utils/internal/MemoryPool.h"
16#include "arcane/utils/FatalErrorException.h"
17#include "arcane/utils/PlatformUtils.h"
18#include "arcane/utils/ValueConvert.h"
20#include <unordered_map>
41 using MapType = std::unordered_map<void*, size_t>;
42 using ValueType = MapType::value_type;
43 using MapIterator = MapType::iterator;
47 explicit AllocatedMap(
const String& name)
53 void removePointer(
void* ptr,
size_t size)
55 std::unique_lock<std::mutex> lg(m_mutex);
56 auto x = m_allocated_memory_map.find(ptr);
57 if (x == m_allocated_memory_map.end()) {
59 String str = String::format(
"MemoryPool '{0}': pointer {1} is not in the allocated map", m_name, ptr);
60 if (m_is_throw_on_error)
63 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);
73 if (m_is_throw_on_error)
76 std::cerr <<
"ERROR: " << str <<
"\n";
79 m_allocated_memory_map.erase(x);
82 void addPointer(
void* ptr,
size_t size)
84 std::unique_lock<std::mutex> lg(m_mutex);
85 auto x = m_allocated_memory_map.find(ptr);
86 if (x != m_allocated_memory_map.end())
87 ARCANE_FATAL(
"MemoryPool '{0}': pointer {1} (for size={2}) is already in the allocated map (with size={3})",
88 m_name, ptr, size, x->second);
90 m_allocated_memory_map.insert(std::make_pair(ptr, size));
95 std::unique_lock<std::mutex> lg(m_mutex);
96 return m_allocated_memory_map.size();
99 bool isThrowOnError()
const {
return m_is_throw_on_error; }
100 void setIsThrowOnError(
bool v) { m_is_throw_on_error = v; }
101 Int32 nbError()
const {
return m_nb_error; }
105 MapType m_allocated_memory_map;
107 std::atomic<Int32> m_nb_error = 0;
108 bool m_is_throw_on_error =
false;
109 mutable std::mutex m_mutex;
119 using MapType = std::unordered_multimap<size_t, void*>;
137 std::unique_lock<std::mutex> lg(m_mutex);
139 auto x = m_free_memory_map.find(size);
140 if (x != m_free_memory_map.end()) {
142 m_free_memory_map.erase(x);
147 void addPointer(
void* ptr,
size_t size)
149 std::unique_lock<std::mutex> lg(m_mutex);
150 m_free_memory_map.insert(std::make_pair(size, ptr));
155 std::unique_lock<std::mutex> lg(m_mutex);
156 return m_free_memory_map.size();
159 void dump(std::ostream& ostr)
161 std::map<size_t, Int32> nb_alloc_per_size;
163 std::unique_lock<std::mutex> lg(m_mutex);
164 for (
const auto& [key, value] : m_free_memory_map) {
165 auto x = nb_alloc_per_size.find(key);
166 if (x == nb_alloc_per_size.end())
167 nb_alloc_per_size.insert(std::make_pair(key, 1));
172 ostr <<
"FreedMap '" << m_name <<
"\n";
173 for (
const auto& [key, value] : nb_alloc_per_size)
174 ostr <<
"Map size=" << key <<
" nb_allocated=" << value <<
" page_modulo=" << (key % 4096) <<
"\n";
180 std::unique_lock<std::mutex> lg(m_mutex);
181 values.reserve(m_free_memory_map.size());
182 for (
const auto& [size, ptr] : m_free_memory_map)
183 values.add(std::make_pair(ptr, size));
184 m_free_memory_map.clear();
189 MapType m_free_memory_map;
191 mutable std::mutex m_mutex;
196 explicit Impl(IMemoryPoolAllocator* allocator,
const String& name)
197 : m_allocator(allocator)
198 , m_allocated_map(name)
203 bool throw_on_error = (v.value() != 0);
204 m_allocated_map.setIsThrowOnError(throw_on_error);
217 void* allocateMemory(
size_t size);
218 void freeMemory(
void* ptr,
size_t size);
219 void dumpStats(std::ostream& ostr);
220 void dumpFreeMap(std::ostream& ostr);
221 void setMaxCachedBlockSize(
size_t v);
222 void freeCachedMemory();
226 IMemoryPoolAllocator* m_allocator =
nullptr;
228 AllocatedMap m_allocated_map;
231 std::atomic<size_t> m_total_allocated = 0;
232 std::atomic<size_t> m_total_free = 0;
233 std::atomic<Int32> m_nb_cached = 0;
234 std::atomic<Int32> m_nb_no_cached = 0;
235 size_t m_max_memory_size_to_pool = 1024 * 64 * 4 * 4;
240 void _freeMemory(
void* ptr);
241 void _addAllocated(
void* ptr,
size_t size);
247void* MemoryPool::Impl::
248allocateMemory(
size_t size)
250 if (m_max_memory_size_to_pool != 0 && size > m_max_memory_size_to_pool) {
252 return m_allocator->allocateMemory(size);
257 m_total_free -= size;
261 ptr = m_allocator->allocateMemory(size);
263 _addAllocated(ptr, size);
270void MemoryPool::Impl::
271freeMemory(
void* ptr,
size_t size)
273 if (m_max_memory_size_to_pool != 0 && size > m_max_memory_size_to_pool)
274 return m_allocator->freeMemory(ptr, size);
276 m_allocated_map.removePointer(ptr, size);
278 m_free_map.addPointer(ptr, size);
279 m_total_allocated -= size;
280 m_total_free += size;
286void MemoryPool::Impl::
287_addAllocated(
void* ptr,
size_t size)
289 m_allocated_map.addPointer(ptr, size);
290 m_total_allocated += size;
296void MemoryPool::Impl::
297dumpStats(std::ostream& ostr)
299 ostr <<
"Stats '" << m_name <<
"' max_block=" << m_max_memory_size_to_pool
300 <<
" TotalAllocated=" << m_total_allocated
301 <<
" TotalFree=" << m_total_free
302 <<
" nb_allocated=" << m_allocated_map.size()
303 <<
" nb_free=" << m_free_map.size()
304 <<
" nb_cached=" << m_nb_cached
305 <<
" nb_no_cached=" << m_nb_no_cached
306 <<
" nb_error=" << m_allocated_map.nbError()
313void MemoryPool::Impl::
314dumpFreeMap(std::ostream& ostr)
316 m_free_map.dump(ostr);
322void MemoryPool::Impl::
323setMaxCachedBlockSize(
size_t v)
325 if (m_allocated_map.size() != 0 || m_free_map.size() != 0)
326 ARCANE_FATAL(
"Can not change maximum cached block size on non empty pool");
327 m_max_memory_size_to_pool = v;
333void MemoryPool::Impl::
336 UniqueArray<std::pair<void*, size_t>> values_to_free;
337 m_free_map.fillFreeMapAndClear(values_to_free);
338 for (
const auto& v : values_to_free) {
339 m_allocator->freeMemory(v.first, v.second);
350MemoryPool(IMemoryPoolAllocator* allocator,
const String& name)
351: m_p(std::make_shared<Impl>(allocator, name))
366void* MemoryPool::allocateMemory(
size_t size)
368 return m_p->allocateMemory(size);
370void MemoryPool::freeMemory(
void* ptr,
size_t size)
372 m_p->freeMemory(ptr, size);
374void MemoryPool::dumpStats(std::ostream& ostr)
376 m_p->dumpStats(ostr);
379dumpFreeMap(std::ostream& ostr)
381 m_p->dumpFreeMap(ostr);
383String MemoryPool::name()
const
388setMaxCachedBlockSize(
size_t v)
390 m_p->setMaxCachedBlockSize(v);
395 m_p->freeCachedMemory();
#define ARCANE_FATAL(...)
Macro envoyant une exception FatalErrorException.
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.
Classe de base des vecteurs 1D de données.
Chaîne de caractères unicode.