Merge branch 'feature-memory_pool.pre' into 'develop'

basic hooks for alternative List/Matrix allocators

See merge request Development/openfoam!742
This commit is contained in:
Mattijs Janssens
2025-05-22 13:46:49 +00:00
27 changed files with 378 additions and 57 deletions

View File

@ -1,3 +1,3 @@
Test-contiguous.C
Test-contiguous.cxx
EXE = $(FOAM_USER_APPBIN)/Test-contiguous

View File

@ -0,0 +1,3 @@
Test-memoryPool1.cxx
EXE = $(FOAM_USER_APPBIN)/Test-memoryPool1

View File

@ -0,0 +1,2 @@
/* EXE_INC = */
/* EXE_LIBS = */

View File

@ -0,0 +1,252 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2025 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "argList.H"
#include "IOstreams.H"
// Enable/disable based on header
#ifdef Foam_MemoryPool_H
#define FOAM_HAS_MEMORY_POOL
#else
#undef FOAM_HAS_MEMORY_POOL
#endif
// options
int min_align_size = 5;
int min_pool_size = 10;
bool use_aligned_alloc(true);
bool use_aligned_dealloc(true);
//- True if size exceeds the min-size for using memory alignment
template<class IntType>
inline bool use_alignment(IntType n) noexcept
{
return (n >= min_align_size);
}
//- True if size exceeds the min-size for using the memory pool
template<class IntType>
inline bool use_memory_pool(IntType n) noexcept
{
return (n >= IntType(min_pool_size));
}
//- Default alignment
inline constexpr std::align_val_t default_alignment() noexcept
{
return std::align_val_t(64);
}
//- Allocate from memory pool (if active) or aligned/normal
template<class T, class IntType>
inline T* my_allocate(IntType n)
{
std::cerr<< "my_allocate(" << n << ")\n";
if (use_aligned_alloc && use_alignment(n))
{
#ifdef FOAM_HAS_MEMORY_POOL
if
(
void *pool_ptr
(
// Consider memory pool for large amounts of data
use_memory_pool(n)
? Foam::MemoryPool::try_allocate(sizeof(T)*n)
: nullptr
);
pool_ptr
)
{
// Placement new
return new (pool_ptr) T[n];
}
else
#endif
{
return new (default_alignment()) T[n];
}
}
else
{
// Plain new
return new T[n];
}
}
//- Deallocate from memory pool or normal
template<class T>
inline void my_deallocate(T* ptr)
{
std::cerr<< "my_deallocate() : " << Foam::name(ptr) << '\n';
#ifdef FOAM_HAS_MEMORY_POOL
if
(
ptr && !Foam::MemoryPool::try_deallocate(ptr)
)
#endif
{
// Plain new
delete[] ptr;
}
}
//- Deallocate from memory pool or aligned/normal
template<class T, class IntType>
inline void my_deallocate(T* ptr, IntType n)
{
std::cerr<< "my_deallocate(" << n << ") : " << Foam::name(ptr) << '\n';
if (use_aligned_dealloc && use_alignment(n))
{
if
(
#ifdef FOAM_HAS_MEMORY_POOL
ptr && !Foam::MemoryPool::try_deallocate(ptr)
#else
ptr
#endif
)
{
::operator delete[](ptr, default_alignment());
}
}
else
{
// Plain new
delete[] ptr;
}
}
using namespace Foam;
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
// Main program:
int main(int argc, char *argv[])
{
argList::noCheckProcessorDirectories();
argList::addOption
(
"min-align",
"INT",
"Min number of elements for memory alignment (default: 5)"
);
argList::addOption
(
"min-pool",
"INT",
"Min number of elements for using memory pool (default: 10)"
);
argList::addOption
(
"count",
"INT",
"Number of elements to test (default: 10)"
);
argList::addBoolOption
(
"no-align",
"Disable aligned alloc/dealloc"
);
argList::addBoolOption
(
"no-align-alloc",
"Disable aligned alloc (default: false)"
);
argList::addBoolOption
(
"no-align-dealloc",
"Disable aligned dealloc (default: false)"
);
#include "setRootCase.H"
label count(10);
args.readIfPresent("count", count);
args.readIfPresent("min-align", min_align_size);
args.readIfPresent("min-pool", min_pool_size);
if (min_pool_size < min_align_size)
{
min_pool_size = min_align_size;
}
if (args.found("no-align"))
{
use_aligned_alloc = false;
use_aligned_dealloc = false;
}
else
{
use_aligned_alloc = !args.found("no-align-alloc");
use_aligned_dealloc = !args.found("no-align-dealloc");
}
Info<< "Testing with " << count << " elements" << nl
<< "min-align: " << int(min_align_size) << " elements" << nl
#ifdef FOAM_HAS_MEMORY_POOL
<< "min-pool: " << int(min_pool_size)
<< " elements, active:" << MemoryPool::active() << nl
#endif
<< "alignment: " << int(default_alignment()) << " bytes" << nl
<< nl;
{
using T = double;
label len = count;
UList<T> list(my_allocate<T>(len), len);
Info<< "List ptr: " << Foam::name(list.data()) << nl;
list = 1.234;
Info<< "List: " << list << nl;
my_deallocate(list.data(), len);
list = UList<T>();
my_deallocate(list.data());
my_deallocate(list.data(), len);
}
return 0;
}
// ************************************************************************* //

View File

@ -193,7 +193,7 @@ Foam::List<Vb::Point> Foam::bodyCentredCubic::initialPoints() const
}
}
return initialPoints.shrink();
return List<Vb::Point>(std::move(initialPoints));
}

View File

@ -254,7 +254,7 @@ Foam::List<Vb::Point> Foam::faceCentredCubic::initialPoints() const
}
}
return initialPoints.shrink();
return List<Vb::Point>(std::move(initialPoints));
}

View File

@ -272,7 +272,7 @@ Foam::List<Vb::Point> Foam::rayShooting::initialPoints() const
}
}
return initialPoints.shrink();
return List<Vb::Point>(std::move(initialPoints));
}

View File

@ -173,7 +173,7 @@ Foam::List<Vb::Point> Foam::uniformGrid::initialPoints() const
}
}
return initialPoints.shrink();
return List<Vb::Point>(std::move(initialPoints));
}

View File

@ -256,7 +256,7 @@ labelList getNonRegionCells(const labelList& cellRegion, const label regionI)
nonRegionCells.append(celli);
}
}
return nonRegionCells.shrink();
return labelList(std::move(nonRegionCells));
}

View File

@ -27,7 +27,6 @@ License
#include "DynamicList.H"
#include "Istream.H"
#include "contiguous.H"
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //

View File

@ -29,7 +29,6 @@ License
#include "IndirectListBase.H"
#include "Ostream.H"
#include "token.H"
#include "contiguous.H"
// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //

View File

@ -28,8 +28,6 @@ License
#include "List.H"
#include "Istream.H"
#include "token.H"
#include "contiguous.H"
#include <memory>
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //

View File

@ -44,17 +44,13 @@ SourceFiles
#include "label.H"
#include "uLabel.H"
#include "zero.H"
#include "contiguous.H"
#include "stdFoam.H"
#include "nullObject.H"
#include "Hash.H"
#include "ListPolicy.H"
#include "ListPolicy.H" // Also includes "contiguous"
#include "autoPtr.H"
// <algorithm> already included by stdFoam.H
#include <iterator>
#include <limits>
#include <type_traits>
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

View File

@ -29,7 +29,6 @@ License
#include "List.H"
#include "FixedList.H"
#include "PtrList.H"
#include "contiguous.H"
// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
@ -42,7 +41,7 @@ void Foam::List<T>::resize_copy(const label count, const label len)
if (FOAM_LIKELY(len > 0))
{
// With sign-check to avoid spurious -Walloc-size-larger-than
// const label oldLen = this->size_;
const label oldLen = this->size_;
const label overlap = Foam::min(count, len);
// Extra safety, not currently necessary:
// const label overlap = Foam::min(Foam::min(count, oldLen), len);
@ -54,22 +53,22 @@ void Foam::List<T>::resize_copy(const label count, const label len)
// Recover overlapping content when resizing
this->size_ = len;
this->v_ = new T[len];
this->v_ = ListPolicy::allocate<T>(len);
// Can dispatch with
// - std::execution::par_unseq
// - std::execution::unseq
std::move(old, (old + overlap), this->v_);
delete[] old;
ListPolicy::deallocate(old, oldLen);
}
else
{
// No overlapping content
delete[] old;
ListPolicy::deallocate(old, oldLen);
this->size_ = len;
this->v_ = new T[len];
this->v_ = ListPolicy::allocate<T>(len);
}
}
else
@ -152,7 +151,7 @@ Foam::List<T>::List(const label len, Foam::zero)
template<class T>
Foam::List<T>::List(Foam::one, const T& val)
:
UList<T>(new T[1], 1)
UList<T>(ListPolicy::allocate<T>(1), 1)
{
this->v_[0] = val;
}
@ -161,7 +160,7 @@ Foam::List<T>::List(Foam::one, const T& val)
template<class T>
Foam::List<T>::List(Foam::one, T&& val)
:
UList<T>(new T[1], 1)
UList<T>(ListPolicy::allocate<T>(1), 1)
{
this->v_[0] = std::move(val);
}
@ -170,9 +169,9 @@ Foam::List<T>::List(Foam::one, T&& val)
template<class T>
Foam::List<T>::List(Foam::one, Foam::zero)
:
UList<T>(new T[1], 1)
UList<T>(ListPolicy::allocate<T>(1), 1)
{
this->v_[0] = Zero;
this->v_[0] = Foam::zero{};
}
@ -311,7 +310,8 @@ Foam::List<T>::List(DynamicList<T, SizeMin>&& list)
template<class T>
Foam::List<T>::~List()
{
delete[] this->v_;
//TODO? May need to verify that size is accurate (for correct alignment)
ListPolicy::deallocate(this->v_, this->size_);
}

View File

@ -34,7 +34,7 @@ inline void Foam::List<T>::doAlloc()
if (this->size_ > 0)
{
// With sign-check to avoid spurious -Walloc-size-larger-than
this->v_ = new T[this->size_];
this->v_ = ListPolicy::allocate<T>(this->size_);
}
}
@ -136,11 +136,8 @@ inline Foam::autoPtr<Foam::List<T>> Foam::List<T>::clone() const
template<class T>
inline void Foam::List<T>::clear()
{
if (this->v_)
{
delete[] this->v_;
this->v_ = nullptr;
}
ListPolicy::deallocate(this->v_, this->size_);
this->v_ = nullptr;
this->size_ = 0;
}

View File

@ -29,8 +29,6 @@ License
#include "List.H"
#include "Istream.H"
#include "token.H"
#include "contiguous.H"
#include <memory>
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //

View File

@ -27,7 +27,6 @@ License
\*---------------------------------------------------------------------------*/
#include "UList.H"
#include "contiguous.H"
#include "labelRange.H"
#include <random>

View File

@ -50,13 +50,11 @@ SourceFiles
#include "uLabel.H"
#include "zero.H"
#include "one.H"
#include "contiguous.H"
#include "stdFoam.H"
#include "nullObject.H"
#include "Hash.H"
#include "ListPolicy.H"
#include "ListPolicy.H" // Also includes "contiguous"
#include <iterator>
#include <vector> // i.e, std::vector
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

View File

@ -29,7 +29,6 @@ License
#include "UList.H"
#include "Ostream.H"
#include "token.H"
#include "contiguous.H"
// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //

View File

@ -34,7 +34,7 @@ Description
#ifndef Foam_ListPolicy_H
#define Foam_ListPolicy_H
#include <type_traits>
#include "contiguous.H" // Also includes <type_traits>
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -86,12 +86,96 @@ template<> struct no_linebreak<word> : std::true_type {};
template<> struct no_linebreak<wordRe> : std::true_type {};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
//
// Memory allocation/deallocation handling - primarily used by List and Matrix
//
// - is_aligned_type() :
// Defines which types may be aligned
//
// - use_alignment(n) :
// Lower threshold for using memory alignment
//
// - use_memory_pool(n) :
// Lower threshold for using a memory pool.
// Must be larger than use_alignment() value.
//
// - use_offload(n) :
// Lower threshold for switching to device offloading
//
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
//- Calculate a reserve size (eg, doubling) based on the request length
//- Consider aligned allocation for the given type?
// Benefits for field data (floating-point, ints, vectorspace),
// but avoid for char data, strings, pointers etc
template<class T>
inline constexpr bool is_aligned_type() noexcept
{
return
(
!std::is_enum_v<T>
&& !std::is_pointer_v<T>
&& !std::is_union_v<T>
&& (sizeof(T) >= 4) // skip small data (eg, char)
&& is_contiguous_v<T>
);
}
//- True if size exceeds the min-size for using memory alignment
template<class IntType>
inline constexpr bool use_alignment(IntType n) noexcept
{
return (n >= IntType(200));
}
//- True if size exceeds the min-size for using the memory pool
template<class IntType>
inline constexpr bool use_memory_pool(IntType n) noexcept
{
return (n >= IntType(3000));
}
//- True if size exceeds the min-size for offloading
template<class IntType>
inline constexpr bool use_offload(IntType n) noexcept
{
return (n >= IntType(1000));
}
template<class T, class IntType>
inline T* allocate(IntType n)
{
// Plain new
return new T[n];
}
template<class T, class IntType>
inline void deallocate(T* ptr)
{
// Plain new
delete[] ptr;
}
template<class T, class IntType>
inline void deallocate(T* ptr, [[maybe_unused]] IntType n)
{
// Plain new
delete[] ptr;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
//- Calculate a reserve size (eg, doubling) based on the requested length
//- and the current capacity
template<int SizeMin, int Numerator, class IntType>
inline IntType reserve_size(IntType requested, IntType capacity)
inline IntType reserve_size(IntType requested, IntType capacity) noexcept
{
static_assert(Numerator > 1, "Invalid numerator");
@ -114,10 +198,10 @@ inline IntType reserve_size(IntType requested, IntType capacity)
}
//- Calculate a reserve size based on the request length
//- Calculate a reserve size based on the requested length
//- and the current capacity
template<int SizeMin, int Numerator, int Denominator, class IntType>
inline IntType reserve_size(IntType requested, IntType capacity)
inline IntType reserve_size(IntType requested, IntType capacity) noexcept
{
static_assert(Numerator > Denominator, "Invalid numerator");
static_assert(Denominator > 0, "Invalid denominator");

View File

@ -29,7 +29,6 @@ License
#include "FieldMapper.H"
#include "FieldM.H"
#include "dictionary.H"
#include "contiguous.H"
#include "mapDistributeBase.H"
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //

View File

@ -244,7 +244,8 @@ inline Foam::Matrix<Form, Type>::Matrix
template<class Form, class Type>
Foam::Matrix<Form, Type>::~Matrix()
{
delete[] v_;
// Accurate alignment information?
ListPolicy::deallocate(this->v_, (mRows_*nCols_));
}
@ -253,12 +254,10 @@ Foam::Matrix<Form, Type>::~Matrix()
template<class Form, class Type>
void Foam::Matrix<Form, Type>::clear()
{
if (v_)
{
delete[] v_;
v_ = nullptr;
}
// Accurate alignment information?
ListPolicy::deallocate(this->v_, (mRows_*nCols_));
v_ = nullptr;
mRows_ = 0;
nCols_ = 0;
}

View File

@ -38,7 +38,8 @@ inline void Foam::Matrix<Form, Type>::doAlloc()
if (len > 0)
{
// With sign-check to avoid spurious -Walloc-size-larger-than
v_ = new Type[len];
this->v_ = ListPolicy::allocate<Type>(len);
}
}

View File

@ -30,8 +30,6 @@ License
#include "Istream.H"
#include "Ostream.H"
#include "token.H"
#include "contiguous.H"
#include "ListPolicy.H"
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //

View File

@ -35,8 +35,8 @@ Description
\*---------------------------------------------------------------------------*/
#ifndef Hash_H
#define Hash_H
#ifndef Foam_Hash_H
#define Foam_Hash_H
#include "Hasher.H"
#include <cstdint>

View File

@ -393,7 +393,7 @@ Foam::labelList Foam::undoableMeshCutter::getSplitFaces() const
}
}
return liveSplitFaces.shrink();
return labelList(std::move(liveSplitFaces));
}