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;
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";
71 String str = String::format(
"MemoryPool '{0}': Incoherent size saved_size={1} arg_size={2}",
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)
163 std::unique_lock<std::mutex>
lg(m_mutex);
164 for (
const auto& [key, value] : m_free_memory_map) {
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;
197 : m_allocator(allocator)
198 , m_allocated_map(name)
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) {
257 m_total_free -= 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))
368 return m_p->allocateMemory(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
390 m_p->setMaxCachedBlockSize(v);
395 m_p->freeCachedMemory();
#define ARCANE_FATAL(...)
Macro envoyant une exception FatalErrorException.
Tableau d'items de types quelconques.
Lecteur des fichiers de maillage via la bibliothèque LIMA.
Interface d'un allocateur pour un MemoryPool.
virtual void * allocateMemory(size_t size)=0
Alloue un bloc pour size octets.
Tableau associatif des pointeurs alloués et la taille associée.
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.
void freeMemory(void *ptr, size_t size) override
Libère le bloc situé à l'adresse address contenant size octets.
void * allocateMemory(size_t size) override
Alloue un bloc pour size octets.
void setMaxCachedBlockSize(size_t v)
Positionne la taille en octet à partir de laquelle on ne conserve pas un bloc dans le cache.
void freeCachedMemory()
Libère la mémoire dans le cache.
Chaîne de caractères unicode.