Skip to content

Commit

Permalink
Merge pull request #1684 from arcaneframework/dev/gg-add-basic-memory…
Browse files Browse the repository at this point in the history
…-pool

Add first implementation of a basic memory pool
  • Loading branch information
grospelliergilles authored Oct 13, 2024
2 parents 87c8efc + 38f1cc6 commit 6f13269
Show file tree
Hide file tree
Showing 5 changed files with 254 additions and 0 deletions.
111 changes: 111 additions & 0 deletions arcane/src/arcane/utils/MemoryPool.cc
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

/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
96 changes: 96 additions & 0 deletions arcane/src/arcane/utils/internal/MemoryPool.h
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
2 changes: 2 additions & 0 deletions arcane/src/arcane/utils/srcs.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ set(ARCANE_SOURCES
ISO88591Transcoder.h
MDSpan.h
MemoryAllocator.h
MemoryPool.cc
MemoryView.h
MemoryView.cc
Misc.cc
Expand Down Expand Up @@ -339,6 +340,7 @@ set(ARCANE_SOURCES
internal/ValueConvertInternal.h
internal/SpecificMemoryCopyList.h
internal/MemoryBuffer.h
internal/MemoryPool.h
)

if (ARCANE_HAS_CXX20)
Expand Down
1 change: 1 addition & 0 deletions arcane/src/arcane/utils/tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
TestHash.cc
TestHashTable.cc
TestMemory.cc
TestMemoryPool.cc
TestPlatform.cc
TestVector2.cc
TestVector3.cc
Expand Down
44 changes: 44 additions & 0 deletions arcane/src/arcane/utils/tests/TestMemoryPool.cc
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();
}

/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/

0 comments on commit 6f13269

Please sign in to comment.