From 7b7229fc13f45bd31d6f632f73b6b9639e8e3c25 Mon Sep 17 00:00:00 2001 From: Mark Olesen <Mark.Olesen@esi-group.com> Date: Mon, 12 May 2025 11:24:45 +0200 Subject: [PATCH] ENH: integrate memory pool support for List allocations - provides an optional memory management using a memory pool. Currently can support Umpire (https://github.com/LLNL/Umpire) When available, its use can be controlled by the FOAM_MEMORY_POOL environment variable, or the memory_pool Optimisation switch (etc/controlDict). Notes: 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 (depending on the field size). The thresholds for aligned, unaligned, memory-pool allocation are still a compile-time option. Made by direct edit of the corrsponding functions. --- etc/bashrc | 5 + etc/controlDict | 3 + etc/cshrc | 5 + src/OSspecific/MSwindows/Make/files | 2 + .../MSwindows/memory/MemoryPool.cxx | 83 +++ src/OSspecific/POSIX/Allwmake | 42 ++ src/OSspecific/POSIX/Make/files | 2 + src/OSspecific/POSIX/Make/options | 5 +- src/OSspecific/POSIX/memory/MemoryPool.cxx | 510 ++++++++++++++++++ .../containers/Lists/policy/ListPolicy.H | 102 +++- src/OpenFOAM/global/argList/argList.C | 4 + src/OpenFOAM/memory/pool/MemoryPool.H | 116 ++++ 12 files changed, 872 insertions(+), 7 deletions(-) create mode 100644 src/OSspecific/MSwindows/memory/MemoryPool.cxx create mode 100644 src/OSspecific/POSIX/memory/MemoryPool.cxx create mode 100644 src/OpenFOAM/memory/pool/MemoryPool.H diff --git a/etc/bashrc b/etc/bashrc index 60030f8ce9c..9fc45639441 100644 --- a/etc/bashrc +++ b/etc/bashrc @@ -132,6 +132,11 @@ projectDir="$HOME/OpenFOAM/OpenFOAM-$WM_PROJECT_VERSION" # projectDir="@PROJECT_DIR@" : # 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. # - overrides the 'trapFpe' controlDict entry # = true | false diff --git a/etc/controlDict b/etc/controlDict index c3e7985415f..2bece2b4606 100644 --- a/etc/controlDict +++ b/etc/controlDict @@ -221,6 +221,9 @@ OptimisationSwitches // Other // ===== + // Optional memory management (sizing in MB) + // memory_pool "host; size=1024; incr=5" + // Trap floating point exception. // Can override with FOAM_SIGFPE env variable (true|false) trapFpe 1; diff --git a/etc/cshrc b/etc/cshrc index b36054eabd4..5e19865b00b 100644 --- a/etc/cshrc +++ b/etc/cshrc @@ -134,6 +134,11 @@ set projectDir=`lsof +p $$ |& sed -ne 's#^[^/]*##;\@/'"$projectName"'[^/]*/etc/c # Or optionally hard-coded (eg, with autoconfig) # 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. # - overrides the 'trapFpe' controlDict entry # = true | false diff --git a/src/OSspecific/MSwindows/Make/files b/src/OSspecific/MSwindows/Make/files index 7c0823f3fce..50c0c9bf652 100644 --- a/src/OSspecific/MSwindows/Make/files +++ b/src/OSspecific/MSwindows/Make/files @@ -3,6 +3,8 @@ MSwindows.C cpuInfo/cpuInfo.C memInfo/memInfo.C +memory/MemoryPool.cxx + signals/sigFpe.cxx signals/sigInt.cxx signals/sigQuit.cxx diff --git a/src/OSspecific/MSwindows/memory/MemoryPool.cxx b/src/OSspecific/MSwindows/memory/MemoryPool.cxx new file mode 100644 index 00000000000..8dca735a50d --- /dev/null +++ b/src/OSspecific/MSwindows/memory/MemoryPool.cxx @@ -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); +} + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // diff --git a/src/OSspecific/POSIX/Allwmake b/src/OSspecific/POSIX/Allwmake index 7bc223e0015..c02a48f9cfc 100755 --- a/src/OSspecific/POSIX/Allwmake +++ b/src/OSspecific/POSIX/Allwmake @@ -2,6 +2,7 @@ cd "${0%/*}" || exit # Run from this directory targetType=libo # Preferred library type . ${WM_PROJECT_DIR:?}/wmake/scripts/AllwmakeParseArguments $* +. ${WM_PROJECT_DIR:?}/wmake/scripts/have_umpire #------------------------------------------------------------------------------ # Hack for MacOS (with Gcc). @@ -59,6 +60,47 @@ then export COMP_FLAGS="-DFOAM_USE_INOTIFY" 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) # Never want/need openmp, especially for static objects wmake -no-openmp $targetType diff --git a/src/OSspecific/POSIX/Make/files b/src/OSspecific/POSIX/Make/files index 29c85884451..ed5d69dc73b 100644 --- a/src/OSspecific/POSIX/Make/files +++ b/src/OSspecific/POSIX/Make/files @@ -4,6 +4,8 @@ cpuInfo/cpuInfo.C cpuTime/cpuTimePosix.C memInfo/memInfo.C +memory/MemoryPool.cxx + signals/sigFpe.cxx signals/sigSegv.cxx signals/sigInt.cxx diff --git a/src/OSspecific/POSIX/Make/options b/src/OSspecific/POSIX/Make/options index 3f86d412a62..2e18d513bdb 100644 --- a/src/OSspecific/POSIX/Make/options +++ b/src/OSspecific/POSIX/Make/options @@ -1 +1,4 @@ -EXE_INC = $(COMP_FLAGS) +/* umpire uses old-style cast etc */ +EXE_INC = $(COMP_FLAGS) $(c++LESSWARN) + +LIBO_LIBS = $(LINK_FLAGS) diff --git a/src/OSspecific/POSIX/memory/MemoryPool.cxx b/src/OSspecific/POSIX/memory/MemoryPool.cxx new file mode 100644 index 00000000000..da65f06a7fc --- /dev/null +++ b/src/OSspecific/POSIX/memory/MemoryPool.cxx @@ -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); +} + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // diff --git a/src/OpenFOAM/containers/Lists/policy/ListPolicy.H b/src/OpenFOAM/containers/Lists/policy/ListPolicy.H index b7289be8fe0..be824287de9 100644 --- a/src/OpenFOAM/containers/Lists/policy/ListPolicy.H +++ b/src/OpenFOAM/containers/Lists/policy/ListPolicy.H @@ -34,6 +34,7 @@ Description #ifndef Foam_ListPolicy_H #define Foam_ListPolicy_H +#include "MemoryPool.H" // Also includes <cstdint> #include "contiguous.H" // Also includes <type_traits> // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // @@ -103,6 +104,18 @@ template<> struct no_linebreak<wordRe> : std::true_type {}; // - use_offload(n) : // 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? @@ -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> inline T* allocate(IntType n) { - // Plain new - return new T[n]; + if constexpr (ListPolicy::is_aligned_type<T>()) + { + // 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> inline void deallocate(T* ptr) { - // Plain new - delete[] ptr; + if constexpr (ListPolicy::is_aligned_type<T>()) + { + 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> inline void deallocate(T* ptr, [[maybe_unused]] IntType n) { - // Plain new - delete[] ptr; + if constexpr (ListPolicy::is_aligned_type<T>()) + { + // 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; + } } diff --git a/src/OpenFOAM/global/argList/argList.C b/src/OpenFOAM/global/argList/argList.C index 0040be93d62..3806e974caa 100644 --- a/src/OpenFOAM/global/argList/argList.C +++ b/src/OpenFOAM/global/argList/argList.C @@ -37,6 +37,7 @@ License #include "IOobject.H" #include "dynamicCode.H" #include "simpleObjectRegistry.H" +#include "MemoryPool.H" #include "sigFpe.H" #include "sigInt.H" #include "sigQuit.H" @@ -2182,6 +2183,9 @@ void Foam::argList::parse sigQuit::set(bannerEnabled()); sigSegv::set(bannerEnabled()); + // Create memory pool (if any) after MPI has been setup + MemoryPool::create(bannerEnabled()); + if (UPstream::master() && bannerEnabled()) { Info<< "fileModificationChecking : " diff --git a/src/OpenFOAM/memory/pool/MemoryPool.H b/src/OpenFOAM/memory/pool/MemoryPool.H new file mode 100644 index 00000000000..56879c3d42f --- /dev/null +++ b/src/OpenFOAM/memory/pool/MemoryPool.H @@ -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 + +// ************************************************************************* // -- GitLab