mirror of
https://develop.openfoam.com/Development/openfoam.git
synced 2025-11-28 03:28:01 +00:00
Merge branch 'feature-memory_pool' into 'develop'
Draft: ENH: integrate memory pool support for List allocations See merge request Development/openfoam!739
This commit is contained in:
@ -132,6 +132,11 @@ projectDir="$HOME/OpenFOAM/OpenFOAM-$WM_PROJECT_VERSION"
|
|||||||
# projectDir="@PROJECT_DIR@"
|
# projectDir="@PROJECT_DIR@"
|
||||||
: # Safety statement (if the user removed all fallback values)
|
: # Safety statement (if the user removed all fallback values)
|
||||||
|
|
||||||
|
# [FOAM_MEMORY_POOL] - Optional memory management
|
||||||
|
# - overrides the 'memory_pool' etc/controlDict entry
|
||||||
|
# = "true | false | host [size=nn] [incr=nn]"
|
||||||
|
#export FOAM_MEMORY_POOL="host"
|
||||||
|
|
||||||
# [FOAM_SIGFPE] - Trap floating-point exceptions.
|
# [FOAM_SIGFPE] - Trap floating-point exceptions.
|
||||||
# - overrides the 'trapFpe' controlDict entry
|
# - overrides the 'trapFpe' controlDict entry
|
||||||
# = true | false
|
# = true | false
|
||||||
|
|||||||
@ -221,6 +221,9 @@ OptimisationSwitches
|
|||||||
// Other
|
// Other
|
||||||
// =====
|
// =====
|
||||||
|
|
||||||
|
// Optional memory management (sizing in MB)
|
||||||
|
// memory_pool "host; size=1024; incr=5"
|
||||||
|
|
||||||
// Trap floating point exception.
|
// Trap floating point exception.
|
||||||
// Can override with FOAM_SIGFPE env variable (true|false)
|
// Can override with FOAM_SIGFPE env variable (true|false)
|
||||||
trapFpe 1;
|
trapFpe 1;
|
||||||
|
|||||||
@ -134,6 +134,11 @@ set projectDir=`lsof +p $$ |& sed -ne 's#^[^/]*##;\@/'"$projectName"'[^/]*/etc/c
|
|||||||
# Or optionally hard-coded (eg, with autoconfig)
|
# Or optionally hard-coded (eg, with autoconfig)
|
||||||
# set projectDir="@PROJECT_DIR@"
|
# set projectDir="@PROJECT_DIR@"
|
||||||
|
|
||||||
|
# [FOAM_MEMORY_POOL] - Optional memory management
|
||||||
|
# - overrides the 'memory_pool' etc/controlDict entry
|
||||||
|
# = "true | false | host [size=nn] [incr=nn]"
|
||||||
|
#setenv FOAM_MEMORY_POOL "host"
|
||||||
|
|
||||||
# [FOAM_SIGFPE] - Trap floating-point exceptions.
|
# [FOAM_SIGFPE] - Trap floating-point exceptions.
|
||||||
# - overrides the 'trapFpe' controlDict entry
|
# - overrides the 'trapFpe' controlDict entry
|
||||||
# = true | false
|
# = true | false
|
||||||
|
|||||||
@ -3,6 +3,8 @@ MSwindows.C
|
|||||||
cpuInfo/cpuInfo.C
|
cpuInfo/cpuInfo.C
|
||||||
memInfo/memInfo.C
|
memInfo/memInfo.C
|
||||||
|
|
||||||
|
memory/MemoryPool.cxx
|
||||||
|
|
||||||
signals/sigFpe.cxx
|
signals/sigFpe.cxx
|
||||||
signals/sigInt.cxx
|
signals/sigInt.cxx
|
||||||
signals/sigQuit.cxx
|
signals/sigQuit.cxx
|
||||||
|
|||||||
83
src/OSspecific/MSwindows/memory/MemoryPool.cxx
Normal file
83
src/OSspecific/MSwindows/memory/MemoryPool.cxx
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
/*---------------------------------------------------------------------------*\
|
||||||
|
========= |
|
||||||
|
\\ / 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 "MemoryPool.H"
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
// bool Foam::MemoryPool::create(const std::string& ctrl, bool verbose)
|
||||||
|
// {
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
bool Foam::MemoryPool::create(bool verbose)
|
||||||
|
{
|
||||||
|
// No banner information since it is currently never an option
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Foam::MemoryPool::destroy(bool verbose)
|
||||||
|
{}
|
||||||
|
|
||||||
|
|
||||||
|
bool Foam::MemoryPool::active() noexcept
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Foam::MemoryPool::suspend() noexcept
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Foam::MemoryPool::resume() noexcept
|
||||||
|
{}
|
||||||
|
|
||||||
|
|
||||||
|
bool Foam::MemoryPool::is_pool(void* ptr)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void* Foam::MemoryPool::try_allocate(std::size_t nbytes)
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Foam::MemoryPool::try_deallocate(void* ptr)
|
||||||
|
{
|
||||||
|
return (!ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
@ -2,6 +2,7 @@
|
|||||||
cd "${0%/*}" || exit # Run from this directory
|
cd "${0%/*}" || exit # Run from this directory
|
||||||
targetType=libo # Preferred library type
|
targetType=libo # Preferred library type
|
||||||
. ${WM_PROJECT_DIR:?}/wmake/scripts/AllwmakeParseArguments $*
|
. ${WM_PROJECT_DIR:?}/wmake/scripts/AllwmakeParseArguments $*
|
||||||
|
. ${WM_PROJECT_DIR:?}/wmake/scripts/have_umpire
|
||||||
|
|
||||||
#------------------------------------------------------------------------------
|
#------------------------------------------------------------------------------
|
||||||
# Hack for MacOS (with Gcc).
|
# Hack for MacOS (with Gcc).
|
||||||
@ -59,6 +60,47 @@ then
|
|||||||
export COMP_FLAGS="-DFOAM_USE_INOTIFY"
|
export COMP_FLAGS="-DFOAM_USE_INOTIFY"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# Have -lumpire, but also -lcamp etc.
|
||||||
|
# Also need to follow the link order
|
||||||
|
get_umpire_libs()
|
||||||
|
{
|
||||||
|
if [ -d "${UMPIRE_LIB_DIR}" ]
|
||||||
|
then
|
||||||
|
set -- $(
|
||||||
|
# Expected link order
|
||||||
|
for name in umpire fmt camp
|
||||||
|
do
|
||||||
|
[ -f "$UMPIRE_LIB_DIR/lib${name}.a" ] && echo "-l$name"
|
||||||
|
done
|
||||||
|
)
|
||||||
|
echo "$@"
|
||||||
|
else
|
||||||
|
echo
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if have_umpire
|
||||||
|
then
|
||||||
|
libNames="$(get_umpire_libs)"
|
||||||
|
|
||||||
|
if [ -n "$libNames" ]
|
||||||
|
then
|
||||||
|
echo " found umpire -- enabling memory pool interface" 1>&2
|
||||||
|
echo " umpire libs: $libNames" 1>&2
|
||||||
|
|
||||||
|
COMP_FLAGS="$COMP_FLAGS -DFOAM_USE_UMPIRE -I${UMPIRE_INC_DIR}"
|
||||||
|
LINK_FLAGS="$LINK_FLAGS -L${UMPIRE_LIB_DIR} $libNames"
|
||||||
|
export COMP_FLAGS LINK_FLAGS
|
||||||
|
else
|
||||||
|
echo " expecting umpire, but did not resolve the libraries" 1>&2
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
|
||||||
# Make object (non-shared by default)
|
# Make object (non-shared by default)
|
||||||
# Never want/need openmp, especially for static objects
|
# Never want/need openmp, especially for static objects
|
||||||
wmake -no-openmp $targetType
|
wmake -no-openmp $targetType
|
||||||
|
|||||||
@ -4,6 +4,8 @@ cpuInfo/cpuInfo.C
|
|||||||
cpuTime/cpuTimePosix.C
|
cpuTime/cpuTimePosix.C
|
||||||
memInfo/memInfo.C
|
memInfo/memInfo.C
|
||||||
|
|
||||||
|
memory/MemoryPool.cxx
|
||||||
|
|
||||||
signals/sigFpe.cxx
|
signals/sigFpe.cxx
|
||||||
signals/sigSegv.cxx
|
signals/sigSegv.cxx
|
||||||
signals/sigInt.cxx
|
signals/sigInt.cxx
|
||||||
|
|||||||
@ -1 +1,4 @@
|
|||||||
EXE_INC = $(COMP_FLAGS)
|
/* umpire uses old-style cast etc */
|
||||||
|
EXE_INC = $(COMP_FLAGS) $(c++LESSWARN)
|
||||||
|
|
||||||
|
LIBO_LIBS = $(LINK_FLAGS)
|
||||||
|
|||||||
510
src/OSspecific/POSIX/memory/MemoryPool.cxx
Normal file
510
src/OSspecific/POSIX/memory/MemoryPool.cxx
Normal file
@ -0,0 +1,510 @@
|
|||||||
|
/*---------------------------------------------------------------------------*\
|
||||||
|
========= |
|
||||||
|
\\ / 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 "MemoryPool.H"
|
||||||
|
#include "debug.H"
|
||||||
|
#include "dictionary.H"
|
||||||
|
#include "sigFpe.H"
|
||||||
|
#include "OSspecific.H" // For getEnv
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
#ifdef FOAM_USE_UMPIRE
|
||||||
|
|
||||||
|
// #include <cerrno>
|
||||||
|
#include <cinttypes>
|
||||||
|
#include <tuple>
|
||||||
|
|
||||||
|
#include "umpire/Allocator.hpp"
|
||||||
|
#include "umpire/ResourceManager.hpp"
|
||||||
|
#include "umpire/strategy/AlignedAllocator.hpp"
|
||||||
|
#include "umpire/strategy/DynamicPoolList.hpp"
|
||||||
|
|
||||||
|
static bool disabled_(false);
|
||||||
|
static umpire::Allocator aligned_allocator;
|
||||||
|
static umpire::Allocator pooled_allocator;
|
||||||
|
static umpire::ResourceManager* manager_(nullptr);
|
||||||
|
static umpire::ResourceManager* suspended_(nullptr);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
#ifdef FOAM_USE_UMPIRE
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
|
||||||
|
// Different supported allocation types
|
||||||
|
enum class Types { undefined, none, host, device, managed };
|
||||||
|
|
||||||
|
typedef std::tuple<Types, std::size_t, std::size_t> ctrlTuple;
|
||||||
|
|
||||||
|
// Extract key=INT, the key includes the '='
|
||||||
|
int getIntParameter(const std::string& key, const std::string& ctrl)
|
||||||
|
{
|
||||||
|
int val(0);
|
||||||
|
|
||||||
|
const auto pos = ctrl.find(key);
|
||||||
|
|
||||||
|
if (pos == std::string::npos)
|
||||||
|
{
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* buf = (ctrl.data() + pos + key.size());
|
||||||
|
|
||||||
|
char *endptr = nullptr;
|
||||||
|
errno = 0;
|
||||||
|
auto parsed = std::strtoimax(buf, &endptr, 10);
|
||||||
|
|
||||||
|
if (errno || endptr == buf)
|
||||||
|
{
|
||||||
|
// Some type of error OR no conversion
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
val = int(parsed);
|
||||||
|
}
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ctrlTuple getControlValues(const std::string& ctrl)
|
||||||
|
{
|
||||||
|
ctrlTuple result(Types::undefined, 0, 0);
|
||||||
|
|
||||||
|
bool checkParam = false;
|
||||||
|
|
||||||
|
// Also find things that look like Switch constants.
|
||||||
|
// Unfortunately need to do this manually since Switch::find()
|
||||||
|
// itself would not manage to parse something like "true; size=10"
|
||||||
|
|
||||||
|
if (ctrl.empty())
|
||||||
|
{
|
||||||
|
// Nothing => undefined
|
||||||
|
}
|
||||||
|
else if
|
||||||
|
(
|
||||||
|
std::string::npos != ctrl.find("false") // ctrl.contains("false")
|
||||||
|
|| std::string::npos != ctrl.find("off") // ctrl.contains("off")
|
||||||
|
|| std::string::npos != ctrl.find("no") // ctrl.contains("no")
|
||||||
|
|| std::string::npos != ctrl.find("none") // ctrl.contains("none")
|
||||||
|
)
|
||||||
|
{
|
||||||
|
std::get<0>(result) = Types::none;
|
||||||
|
}
|
||||||
|
else if
|
||||||
|
(
|
||||||
|
std::string::npos != ctrl.find("true") // ctrl.contains("true")
|
||||||
|
|| std::string::npos != ctrl.find("on") // ctrl.contains("on")
|
||||||
|
|| std::string::npos != ctrl.find("yes") // ctrl.contains("yes")
|
||||||
|
|
||||||
|
|| std::string::npos != ctrl.find("host") // ctrl.contains("host")
|
||||||
|
|| std::string::npos != ctrl.find("system") // ctrl.contains("system")
|
||||||
|
)
|
||||||
|
{
|
||||||
|
std::get<0>(result) = Types::host;
|
||||||
|
checkParam = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// These need more testing
|
||||||
|
else if
|
||||||
|
(
|
||||||
|
std::string::npos != ctrl.find("device") // ctrl.contains("device")
|
||||||
|
)
|
||||||
|
{
|
||||||
|
std::get<0>(result) = Types::device;
|
||||||
|
checkParam = true;
|
||||||
|
}
|
||||||
|
else if
|
||||||
|
(
|
||||||
|
std::string::npos != ctrl.find("managed") // ctrl.contains("managed")
|
||||||
|
)
|
||||||
|
{
|
||||||
|
std::get<0>(result) = Types::managed;
|
||||||
|
checkParam = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (checkParam)
|
||||||
|
{
|
||||||
|
std::get<1>(result) = getIntParameter("size=", ctrl);
|
||||||
|
std::get<2>(result) = getIntParameter("incr=", ctrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool create_from(const ctrlTuple& controls, bool verbose)
|
||||||
|
{
|
||||||
|
using namespace Foam;
|
||||||
|
|
||||||
|
if (manager_ || suspended_)
|
||||||
|
{
|
||||||
|
// Already created
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Type, initial size, increment
|
||||||
|
auto [which, size, incr] = controls;
|
||||||
|
|
||||||
|
// std::cerr
|
||||||
|
// << "which=" << int(which)
|
||||||
|
// << ", size=" << int(size)
|
||||||
|
// << ", incr=" << int(incr) << '\n';
|
||||||
|
|
||||||
|
|
||||||
|
constexpr size_t MegaByte(1024*1024);
|
||||||
|
|
||||||
|
switch (which)
|
||||||
|
{
|
||||||
|
case Types::undefined :
|
||||||
|
{
|
||||||
|
if (verbose)
|
||||||
|
{
|
||||||
|
Info<< "memory pool : unused" << nl;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case Types::none :
|
||||||
|
{
|
||||||
|
if (verbose)
|
||||||
|
{
|
||||||
|
Info<< "memory pool : disabled" << nl;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case Types::host :
|
||||||
|
{
|
||||||
|
// Default sizing parameters
|
||||||
|
if (!size) size = 1024;
|
||||||
|
if (!incr) incr = 5;
|
||||||
|
|
||||||
|
auto& rm = umpire::ResourceManager::getInstance();
|
||||||
|
manager_ = &rm;
|
||||||
|
|
||||||
|
aligned_allocator =
|
||||||
|
rm.makeAllocator<umpire::strategy::AlignedAllocator>
|
||||||
|
(
|
||||||
|
"aligned_allocator",
|
||||||
|
rm.getAllocator("HOST"),
|
||||||
|
|
||||||
|
// alignment
|
||||||
|
256
|
||||||
|
);
|
||||||
|
|
||||||
|
pooled_allocator =
|
||||||
|
rm.makeAllocator<umpire::strategy::DynamicPoolList>
|
||||||
|
(
|
||||||
|
"openfoam_HOST_pool",
|
||||||
|
aligned_allocator,
|
||||||
|
|
||||||
|
// initial block allocation size
|
||||||
|
(size*MegaByte),
|
||||||
|
|
||||||
|
// incremental block allocation size
|
||||||
|
(incr*MegaByte)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (verbose)
|
||||||
|
{
|
||||||
|
Info<< "memory pool : host (size="
|
||||||
|
<< int(size) << "MB, incr="
|
||||||
|
<< int(incr) << "MB)\n";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case Types::device :
|
||||||
|
{
|
||||||
|
auto& rm = umpire::ResourceManager::getInstance();
|
||||||
|
manager_ = &rm;
|
||||||
|
|
||||||
|
aligned_allocator = rm.getAllocator("DEVICE");
|
||||||
|
|
||||||
|
pooled_allocator =
|
||||||
|
rm.makeAllocator<umpire::strategy::DynamicPoolList>
|
||||||
|
(
|
||||||
|
"openfoam_DEVICE_pool",
|
||||||
|
aligned_allocator
|
||||||
|
);
|
||||||
|
|
||||||
|
if (verbose)
|
||||||
|
{
|
||||||
|
Info<< "memory pool : device" << nl;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case Types::managed :
|
||||||
|
{
|
||||||
|
// Default sizing parameters
|
||||||
|
if (!size) size = 10*1024;
|
||||||
|
if (!incr) incr = 10;
|
||||||
|
|
||||||
|
auto& rm = umpire::ResourceManager::getInstance();
|
||||||
|
manager_ = &rm;
|
||||||
|
|
||||||
|
aligned_allocator = rm.getAllocator("UM");
|
||||||
|
|
||||||
|
pooled_allocator =
|
||||||
|
rm.makeAllocator<umpire::strategy::DynamicPoolList>
|
||||||
|
(
|
||||||
|
"openfoam_UM_pool",
|
||||||
|
aligned_allocator,
|
||||||
|
|
||||||
|
// initial block allocation size
|
||||||
|
(size*MegaByte),
|
||||||
|
|
||||||
|
// incremental block allocation size
|
||||||
|
(incr*MegaByte)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (verbose)
|
||||||
|
{
|
||||||
|
Info<< "memory pool : managed (size="
|
||||||
|
<< int(size) << "MB, incr="
|
||||||
|
<< int(incr) << "MB)\n";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (which != Types::undefined && which != Types::none);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // End anonymous namespace
|
||||||
|
|
||||||
|
#endif // FOAM_USE_UMPIRE
|
||||||
|
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
// bool Foam::MemoryPool::create(const std::string& ctrl, bool verbose)
|
||||||
|
// {
|
||||||
|
// #ifdef FOAM_USE_UMPIRE
|
||||||
|
// if (manager_ || suspended_)
|
||||||
|
// {
|
||||||
|
// // Already created
|
||||||
|
// return true;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// auto controls = getControlValues(ctrl);
|
||||||
|
//
|
||||||
|
// return create_from(controls, verbose);
|
||||||
|
// #else
|
||||||
|
// return false;
|
||||||
|
// #endif
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
bool Foam::MemoryPool::create(bool verbose)
|
||||||
|
{
|
||||||
|
#ifdef FOAM_USE_UMPIRE
|
||||||
|
if (disabled_)
|
||||||
|
{
|
||||||
|
// Disallowed
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else if (manager_ || suspended_)
|
||||||
|
{
|
||||||
|
// Already created
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// First check environment
|
||||||
|
auto controls = getControlValues(Foam::getEnv("FOAM_MEMORY_POOL"));
|
||||||
|
|
||||||
|
if (std::get<0>(controls) == Types::none)
|
||||||
|
{
|
||||||
|
// Disabled from environment - has highest priority
|
||||||
|
disabled_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Currently no easy way to handle <system>/controlDict...
|
||||||
|
|
||||||
|
// Fallback from etc/controlDict
|
||||||
|
if (std::get<0>(controls) == Types::undefined)
|
||||||
|
{
|
||||||
|
// From central etc/controlDict
|
||||||
|
const auto& dict = Foam::debug::optimisationSwitches();
|
||||||
|
|
||||||
|
if (auto* eptr = dict.findStream("memory_pool", keyType::LITERAL))
|
||||||
|
{
|
||||||
|
const token& firstToken = eptr->front();
|
||||||
|
|
||||||
|
if (firstToken.isStringType())
|
||||||
|
{
|
||||||
|
controls = getControlValues(firstToken.stringToken());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return create_from(controls, verbose);
|
||||||
|
#else
|
||||||
|
if (verbose)
|
||||||
|
{
|
||||||
|
Info<< "memory pool : not available" << nl;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Foam::MemoryPool::destroy(bool verbose)
|
||||||
|
{
|
||||||
|
// Nothing currently needed but could add in something like this:
|
||||||
|
|
||||||
|
// if (manager_ || suspended_)
|
||||||
|
// {
|
||||||
|
// pooled_allocator.release();
|
||||||
|
// }
|
||||||
|
|
||||||
|
// However, need to find the proper sequence within
|
||||||
|
// Foam::exit() or UPstream::exit() ...
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Foam::MemoryPool::active() noexcept
|
||||||
|
{
|
||||||
|
#ifdef FOAM_USE_UMPIRE
|
||||||
|
return bool(manager_);
|
||||||
|
#else
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Foam::MemoryPool::suspend() noexcept
|
||||||
|
{
|
||||||
|
#ifdef FOAM_USE_UMPIRE
|
||||||
|
bool status(suspended_);
|
||||||
|
if (manager_) // <- and (!suspended_)
|
||||||
|
{
|
||||||
|
std::swap(manager_, suspended_);
|
||||||
|
}
|
||||||
|
return status;
|
||||||
|
#else
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Foam::MemoryPool::resume() noexcept
|
||||||
|
{
|
||||||
|
#ifdef FOAM_USE_UMPIRE
|
||||||
|
if (suspended_) // <- and (!manager_)
|
||||||
|
{
|
||||||
|
std::swap(manager_, suspended_);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Foam::MemoryPool::is_pool(void* ptr)
|
||||||
|
{
|
||||||
|
#ifdef FOAM_USE_UMPIRE
|
||||||
|
if (ptr)
|
||||||
|
{
|
||||||
|
if (manager_)
|
||||||
|
{
|
||||||
|
return manager_->hasAllocator(ptr);
|
||||||
|
}
|
||||||
|
else if (suspended_)
|
||||||
|
{
|
||||||
|
return suspended_->hasAllocator(ptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void* Foam::MemoryPool::try_allocate(std::size_t nbytes)
|
||||||
|
{
|
||||||
|
void* ptr = nullptr;
|
||||||
|
|
||||||
|
#ifdef FOAM_USE_UMPIRE
|
||||||
|
if (manager_)
|
||||||
|
{
|
||||||
|
ptr = pooled_allocator.allocate(nbytes);
|
||||||
|
|
||||||
|
// std::cerr<< "allocate(" << int(nbytes) << ")\n";
|
||||||
|
|
||||||
|
// Optionally fill with NaN (depends on current flags)
|
||||||
|
Foam::sigFpe::fillNan_if(ptr, nbytes);
|
||||||
|
|
||||||
|
if (!ptr)
|
||||||
|
{
|
||||||
|
// Pout<< "umpire failed to allocate memory\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Foam::MemoryPool::try_deallocate(void* ptr)
|
||||||
|
{
|
||||||
|
#ifdef FOAM_USE_UMPIRE
|
||||||
|
if (ptr)
|
||||||
|
{
|
||||||
|
if (manager_)
|
||||||
|
{
|
||||||
|
if (manager_->hasAllocator(ptr)) // <- ie, is_pool()
|
||||||
|
{
|
||||||
|
// std::cerr<< "deallocate()\n";
|
||||||
|
manager_->deallocate(ptr);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (suspended_)
|
||||||
|
{
|
||||||
|
// Deallocate even if nominally suspended
|
||||||
|
|
||||||
|
if (suspended_->hasAllocator(ptr)) // <- ie, is_pool()
|
||||||
|
{
|
||||||
|
// std::cerr<< "deallocate()\n";
|
||||||
|
suspended_->deallocate(ptr);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return (!ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
@ -34,6 +34,7 @@ Description
|
|||||||
#ifndef Foam_ListPolicy_H
|
#ifndef Foam_ListPolicy_H
|
||||||
#define Foam_ListPolicy_H
|
#define Foam_ListPolicy_H
|
||||||
|
|
||||||
|
#include "MemoryPool.H" // Also includes <cstdint>
|
||||||
#include "contiguous.H" // Also includes <type_traits>
|
#include "contiguous.H" // Also includes <type_traits>
|
||||||
|
|
||||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
@ -103,6 +104,18 @@ template<> struct no_linebreak<wordRe> : std::true_type {};
|
|||||||
// - use_offload(n) :
|
// - use_offload(n) :
|
||||||
// Lower threshold for switching to device offloading
|
// Lower threshold for switching to device offloading
|
||||||
//
|
//
|
||||||
|
//
|
||||||
|
// Use of the memory-pool is controlled by the 'is_aligned_type()' test
|
||||||
|
// and the minimum field size, controlled by the 'use_memory_pool()' test.
|
||||||
|
//
|
||||||
|
// If the memory-pool is not enabled or not required according to the two
|
||||||
|
// above tests, the allocation falls back to either an aligned or unaligned
|
||||||
|
// allocation.
|
||||||
|
//
|
||||||
|
// The decision about when to choose aligned vs unaligned allocation
|
||||||
|
// is still a compile-time option. Made by direct edit of the
|
||||||
|
// appropriate functions.
|
||||||
|
//
|
||||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
//- Consider aligned allocation for the given type?
|
//- Consider aligned allocation for the given type?
|
||||||
@ -146,27 +159,104 @@ inline constexpr bool use_offload(IntType n) noexcept
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//- Default alignment for larger fields
|
||||||
|
inline constexpr std::align_val_t default_alignment() noexcept
|
||||||
|
{
|
||||||
|
return std::align_val_t(256);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//- Allocate from memory pool (if active), or aligned, or normal
|
||||||
template<class T, class IntType>
|
template<class T, class IntType>
|
||||||
inline T* allocate(IntType n)
|
inline T* allocate(IntType n)
|
||||||
{
|
{
|
||||||
// Plain new
|
if constexpr (ListPolicy::is_aligned_type<T>())
|
||||||
return new T[n];
|
{
|
||||||
|
// Note: threshold for use_memory_pool() >= use_alignment()
|
||||||
|
|
||||||
|
if (ListPolicy::use_alignment(n))
|
||||||
|
{
|
||||||
|
if
|
||||||
|
(
|
||||||
|
void *pool_ptr
|
||||||
|
(
|
||||||
|
// Consider memory pool for large amounts of data
|
||||||
|
ListPolicy::use_memory_pool(n)
|
||||||
|
? Foam::MemoryPool::try_allocate(sizeof(T)*n)
|
||||||
|
: nullptr
|
||||||
|
);
|
||||||
|
pool_ptr
|
||||||
|
)
|
||||||
|
{
|
||||||
|
// Placement new
|
||||||
|
return new (pool_ptr) T[n];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return new (ListPolicy::default_alignment()) T[n];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Plain new
|
||||||
|
return new T[n];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Plain new
|
||||||
|
return new T[n];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//- Deallocate from memory pool, or normal
|
||||||
template<class T, class IntType>
|
template<class T, class IntType>
|
||||||
inline void deallocate(T* ptr)
|
inline void deallocate(T* ptr)
|
||||||
{
|
{
|
||||||
// Plain new
|
if constexpr (ListPolicy::is_aligned_type<T>())
|
||||||
delete[] ptr;
|
{
|
||||||
|
if (ptr && !Foam::MemoryPool::try_deallocate(ptr))
|
||||||
|
{
|
||||||
|
// Plain new
|
||||||
|
delete[] ptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Plain new
|
||||||
|
delete[] ptr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//- Deallocate from memory pool, or aligned, or normal
|
||||||
template<class T, class IntType>
|
template<class T, class IntType>
|
||||||
inline void deallocate(T* ptr, [[maybe_unused]] IntType n)
|
inline void deallocate(T* ptr, [[maybe_unused]] IntType n)
|
||||||
{
|
{
|
||||||
// Plain new
|
if constexpr (ListPolicy::is_aligned_type<T>())
|
||||||
delete[] ptr;
|
{
|
||||||
|
// Note: threshold for use_memory_pool() >= use_alignment()
|
||||||
|
|
||||||
|
if (ListPolicy::use_alignment(n))
|
||||||
|
{
|
||||||
|
if (ptr && !Foam::MemoryPool::try_deallocate(ptr))
|
||||||
|
{
|
||||||
|
// Alignment depends on the number of elements
|
||||||
|
::operator delete[](ptr, ListPolicy::default_alignment());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Plain new
|
||||||
|
delete[] ptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Plain new
|
||||||
|
delete[] ptr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -37,6 +37,7 @@ License
|
|||||||
#include "IOobject.H"
|
#include "IOobject.H"
|
||||||
#include "dynamicCode.H"
|
#include "dynamicCode.H"
|
||||||
#include "simpleObjectRegistry.H"
|
#include "simpleObjectRegistry.H"
|
||||||
|
#include "MemoryPool.H"
|
||||||
#include "sigFpe.H"
|
#include "sigFpe.H"
|
||||||
#include "sigInt.H"
|
#include "sigInt.H"
|
||||||
#include "sigQuit.H"
|
#include "sigQuit.H"
|
||||||
@ -2180,6 +2181,9 @@ void Foam::argList::parse
|
|||||||
sigQuit::set(bannerEnabled());
|
sigQuit::set(bannerEnabled());
|
||||||
sigSegv::set(bannerEnabled());
|
sigSegv::set(bannerEnabled());
|
||||||
|
|
||||||
|
// Create memory pool (if any) after MPI has been setup
|
||||||
|
MemoryPool::create(bannerEnabled());
|
||||||
|
|
||||||
if (UPstream::master() && bannerEnabled())
|
if (UPstream::master() && bannerEnabled())
|
||||||
{
|
{
|
||||||
Info<< "fileModificationChecking : "
|
Info<< "fileModificationChecking : "
|
||||||
|
|||||||
116
src/OpenFOAM/memory/pool/MemoryPool.H
Normal file
116
src/OpenFOAM/memory/pool/MemoryPool.H
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
/*---------------------------------------------------------------------------*\
|
||||||
|
========= |
|
||||||
|
\\ / 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/>.
|
||||||
|
|
||||||
|
Class
|
||||||
|
Foam::MemoryPool
|
||||||
|
|
||||||
|
Description
|
||||||
|
Optional memory management using a memory pool such as Umpire
|
||||||
|
(https://github.com/LLNL/Umpire).
|
||||||
|
|
||||||
|
When compiled with Umpire, its use can be controlled by the
|
||||||
|
\c FOAM_MEMORY_POOL environment variable, or the
|
||||||
|
\c memory_pool Optimisation switch (etc/controlDict).
|
||||||
|
|
||||||
|
It currently looks for any of the following entries, in this order:
|
||||||
|
- true - same as \em "host"
|
||||||
|
- false/none - disabled.
|
||||||
|
- \em "host" - uses host memory pool
|
||||||
|
- \em "system" - same as \em "host"
|
||||||
|
- \em "device" - uses device memory pool
|
||||||
|
- \em "managed" - uses managed host/device memory pool
|
||||||
|
.
|
||||||
|
|
||||||
|
The parameters "size=nn" and "incr=nn" (in MegaBytes) can be used
|
||||||
|
to specify alternatives to the default sizing.
|
||||||
|
|
||||||
|
\*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#ifndef Foam_MemoryPool_H
|
||||||
|
#define Foam_MemoryPool_H
|
||||||
|
|
||||||
|
#include <cstdint> // For size_t
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
namespace Foam
|
||||||
|
{
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------*\
|
||||||
|
Class MemoryPool Declaration
|
||||||
|
\*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
class MemoryPool
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
// Constructors
|
||||||
|
|
||||||
|
//- Create a memory pool instance (if not already active).
|
||||||
|
// Uses environment or etc/controlDict entry
|
||||||
|
static bool create(bool verbose = false);
|
||||||
|
|
||||||
|
|
||||||
|
// Destructor
|
||||||
|
|
||||||
|
//- Remove the memory pool instance (currently does nothing)
|
||||||
|
static void destroy(bool verbose = false);
|
||||||
|
|
||||||
|
|
||||||
|
// Member Functions
|
||||||
|
|
||||||
|
//- True if pool is active (ie, created and not suspended)
|
||||||
|
static bool active() noexcept;
|
||||||
|
|
||||||
|
//- Suspend use of memory pool (for allocation).
|
||||||
|
// \return previous suspend status
|
||||||
|
static bool suspend() noexcept;
|
||||||
|
|
||||||
|
//- Resume use of memory pool (if previously active)
|
||||||
|
static void resume() noexcept;
|
||||||
|
|
||||||
|
//- Test if given pointer belongs to the pool
|
||||||
|
static bool is_pool(void *ptr);
|
||||||
|
|
||||||
|
//- Allocate from pool (if active).
|
||||||
|
// \returns nullptr if the pool is not active
|
||||||
|
static void* try_allocate(std::size_t nbytes);
|
||||||
|
|
||||||
|
//- Deallocate a pointer managed by the pool
|
||||||
|
// \returns True if a nullptr (no-op) or when the pointer was
|
||||||
|
// managed by the pool.
|
||||||
|
static bool try_deallocate(void *ptr);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
} // End namespace Foam
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ************************************************************************* //
|
||||||
Reference in New Issue
Block a user