-
Notifications
You must be signed in to change notification settings - Fork 14
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1684 from arcaneframework/dev/gg-add-basic-memory…
…-pool Add first implementation of a basic memory pool
- Loading branch information
Showing
5 changed files
with
254 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*- | ||
//----------------------------------------------------------------------------- | ||
// Copyright 2000-2024 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com) | ||
// See the top-level COPYRIGHT file for details. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
//----------------------------------------------------------------------------- | ||
/*---------------------------------------------------------------------------*/ | ||
/* MemoryPool.cc (C) 2000-2024 */ | ||
/* */ | ||
/* Classe pour gérer une liste de zone allouées. */ | ||
/*---------------------------------------------------------------------------*/ | ||
/*---------------------------------------------------------------------------*/ | ||
|
||
#include "arcane/utils/internal/MemoryPool.h" | ||
|
||
#include "arcane/utils/FatalErrorException.h" | ||
|
||
/*---------------------------------------------------------------------------*/ | ||
/*---------------------------------------------------------------------------*/ | ||
|
||
namespace Arcane::impl | ||
{ | ||
|
||
/*---------------------------------------------------------------------------*/ | ||
/*---------------------------------------------------------------------------*/ | ||
|
||
MemoryPool:: | ||
MemoryPool(IMemoryPoolAllocator* allocator) | ||
: m_allocator(allocator) | ||
{ | ||
} | ||
|
||
/*---------------------------------------------------------------------------*/ | ||
/*---------------------------------------------------------------------------*/ | ||
|
||
MemoryPool:: | ||
~MemoryPool() | ||
{ | ||
} | ||
|
||
/*---------------------------------------------------------------------------*/ | ||
/*---------------------------------------------------------------------------*/ | ||
|
||
void* MemoryPool:: | ||
allocateMemory(size_t size) | ||
{ | ||
auto x = m_free_memory_map.find(size); | ||
void* ptr = nullptr; | ||
if (x != m_free_memory_map.end()) { | ||
ptr = x->second; | ||
m_free_memory_map.erase(x); | ||
m_total_free -= size; | ||
} | ||
else | ||
ptr = m_allocator->allocateMemory(size); | ||
_addAllocated(ptr, size); | ||
return ptr; | ||
} | ||
|
||
/*---------------------------------------------------------------------------*/ | ||
/*---------------------------------------------------------------------------*/ | ||
|
||
void MemoryPool:: | ||
freeMemory(void* ptr, size_t size) | ||
{ | ||
auto x = m_allocated_memory_map.find(ptr); | ||
if (x == m_allocated_memory_map.end()) | ||
ARCANE_FATAL("pointer {0} is not in the allocated map", ptr); | ||
size_t allocated_size = x->second; | ||
if (size != allocated_size) | ||
ARCANE_FATAL("Incoherent size saved_size={0} arg_size={1}", allocated_size, size); | ||
m_allocated_memory_map.erase(x); | ||
m_free_memory_map.insert(std::make_pair(allocated_size, ptr)); | ||
m_total_allocated -= allocated_size; | ||
m_total_free += allocated_size; | ||
} | ||
|
||
/*---------------------------------------------------------------------------*/ | ||
/*---------------------------------------------------------------------------*/ | ||
|
||
void MemoryPool:: | ||
_addAllocated(void* ptr, size_t size) | ||
{ | ||
#ifdef ARCANE_CHECK | ||
if (m_allocated_memory_map.find(ptr) != m_allocated_memory_map.end()) | ||
ARCANE_FATAL("pointer {0} (for size={1}) is already in the allocated map", ptr, size); | ||
#endif | ||
m_allocated_memory_map.insert(std::make_pair(ptr, size)); | ||
m_total_allocated += size; | ||
} | ||
|
||
/*---------------------------------------------------------------------------*/ | ||
/*---------------------------------------------------------------------------*/ | ||
|
||
void MemoryPool:: | ||
dumpStats() | ||
{ | ||
std::cout << "Stats TotalAllocated=" << m_total_allocated | ||
<< " TotalFree=" << m_total_free | ||
<< " nb_allocated=" << m_allocated_memory_map.size() | ||
<< " nb_free=" << m_free_memory_map.size() | ||
<< "\n"; | ||
} | ||
|
||
/*---------------------------------------------------------------------------*/ | ||
/*---------------------------------------------------------------------------*/ | ||
|
||
} // namespace Arcane::impl | ||
|
||
/*---------------------------------------------------------------------------*/ | ||
/*---------------------------------------------------------------------------*/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*- | ||
//----------------------------------------------------------------------------- | ||
// Copyright 2000-2024 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com) | ||
// See the top-level COPYRIGHT file for details. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
//----------------------------------------------------------------------------- | ||
/*---------------------------------------------------------------------------*/ | ||
/* MemoryPool.h (C) 2000-2024 */ | ||
/* */ | ||
/* Classe pour gérer une liste de zone allouées. */ | ||
/*---------------------------------------------------------------------------*/ | ||
#ifndef ARCANE_UTILS_INTERNAL_MEMORYPOOL_H | ||
#define ARCANE_UTILS_INTERNAL_MEMORYPOOL_H | ||
/*---------------------------------------------------------------------------*/ | ||
/*---------------------------------------------------------------------------*/ | ||
|
||
#include "arcane/utils/ArcaneGlobal.h" | ||
|
||
#include <unordered_map> | ||
#include <atomic> | ||
|
||
/*---------------------------------------------------------------------------*/ | ||
/*---------------------------------------------------------------------------*/ | ||
|
||
namespace Arcane::impl | ||
{ | ||
|
||
/*---------------------------------------------------------------------------*/ | ||
/*---------------------------------------------------------------------------*/ | ||
/*! | ||
* \internal | ||
* \brief Interface d'un allocateur pour un MemoryPool. | ||
* | ||
* Cette interface fonctionne à la manière d'un malloc/free à ceci prêt qu'il | ||
* faut fournir la taille alloué pour un bloc pour la libération de ce dernier. | ||
* L'utilisateur de cette interface doit donc gérer la conservation de cette | ||
* information. | ||
*/ | ||
class ARCANE_UTILS_EXPORT IMemoryPoolAllocator | ||
{ | ||
public: | ||
|
||
virtual ~IMemoryPoolAllocator() = default; | ||
|
||
public: | ||
|
||
//! Alloue un bloc pour \a size octets | ||
virtual void* allocateMemory(size_t size) = 0; | ||
//! Libère le bloc situé à l'adresse \a address contenant \a size octets | ||
virtual void freeMemory(void* address, size_t size) = 0; | ||
}; | ||
|
||
/*---------------------------------------------------------------------------*/ | ||
/*---------------------------------------------------------------------------*/ | ||
/*! | ||
* \internal | ||
* \brief Classe pour gérer une liste de zone allouées. | ||
*/ | ||
class ARCANE_UTILS_EXPORT MemoryPool | ||
: public IMemoryPoolAllocator | ||
{ | ||
public: | ||
|
||
explicit MemoryPool(IMemoryPoolAllocator* allocator); | ||
~MemoryPool(); | ||
|
||
public: | ||
|
||
void* allocateMemory(size_t size) override; | ||
void freeMemory(void* ptr, size_t size) override; | ||
void dumpStats(); | ||
|
||
private: | ||
|
||
IMemoryPoolAllocator* m_allocator = nullptr; | ||
// Contient une liste de couples (taille_mémoire,pointeur) de mémoire allouée. | ||
std::unordered_multimap<size_t, void*> m_free_memory_map; | ||
std::unordered_map<void*, size_t> m_allocated_memory_map; | ||
std::atomic<size_t> m_total_allocated = 0; | ||
std::atomic<size_t> m_total_free = 0; | ||
|
||
private: | ||
|
||
void _freeMemory(void* ptr); | ||
void _addAllocated(void* ptr, size_t size); | ||
}; | ||
|
||
/*---------------------------------------------------------------------------*/ | ||
/*---------------------------------------------------------------------------*/ | ||
|
||
} // namespace Arcane::impl | ||
|
||
/*---------------------------------------------------------------------------*/ | ||
/*---------------------------------------------------------------------------*/ | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*- | ||
//----------------------------------------------------------------------------- | ||
// Copyright 2000-2024 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com) | ||
// See the top-level COPYRIGHT file for details. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
//----------------------------------------------------------------------------- | ||
|
||
#include <gtest/gtest.h> | ||
|
||
#include "arcane/utils/internal/MemoryPool.h" | ||
|
||
/*---------------------------------------------------------------------------*/ | ||
/*---------------------------------------------------------------------------*/ | ||
|
||
using namespace Arcane; | ||
using namespace Arcane::impl; | ||
|
||
/*---------------------------------------------------------------------------*/ | ||
/*---------------------------------------------------------------------------*/ | ||
|
||
class MyMemoryPoolAllocator | ||
: public IMemoryPoolAllocator | ||
{ | ||
void* allocateMemory(size_t size) override { return std::malloc(size); } | ||
void freeMemory(void* address,size_t) override { std::free(address); } | ||
}; | ||
|
||
/*---------------------------------------------------------------------------*/ | ||
/*---------------------------------------------------------------------------*/ | ||
|
||
TEST(MemoryPool, Misc) | ||
{ | ||
MyMemoryPoolAllocator my_allocator; | ||
MemoryPool memory_pool(&my_allocator); | ||
|
||
void* a1 = memory_pool.allocateMemory(25); | ||
void* a2 = memory_pool.allocateMemory(47); | ||
memory_pool.freeMemory(a1, 25); | ||
memory_pool.freeMemory(a2, 47); | ||
memory_pool.dumpStats(); | ||
} | ||
|
||
/*---------------------------------------------------------------------------*/ | ||
/*---------------------------------------------------------------------------*/ |