diff --git a/etc/bashrc b/etc/bashrc index 60030f8ce9cd5ced9f291672e201448c4c8492a1..9fc456394416b141804d7e5c3da579b3a05875e5 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 c3e7985415fd8f91f267cf87e185fd2a36a3ad57..2bece2b460609b3b23c38517e0a3da87568bf22d 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 b36054eabd4975b995b4f0d52b547b2fb6fab26e..5e19865b00ba584ed5b4f6c6ff5fca73f18622ec 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 7c0823f3fcee6c7bada9f3bd48ebd1e686594e07..50c0c9bf652de1a5d2eb1ed70d11a49348e60f5f 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 0000000000000000000000000000000000000000..8dca735a50d658931f29148de7821e5cd2e2297e --- /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 7bc223e001502f1431b0e73f4732b40d9d033da1..c02a48f9cfc3a6a44b889768cd4d49cf0b760fc8 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 29c8588445158e0820febf024a803f407fe03460..ed5d69dc73b037b6bdcce707961da2d7d6e80aaf 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 3f86d412a62b7c58d486f100cbde05dcc9de5827..2e18d513bdb61a9a7bf827570ef63deefb05e5d1 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 0000000000000000000000000000000000000000..da65f06a7fc760530d6486730972be9b3e7b1685 --- /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 b7289be8fe076c14f3cbb9f6eec11ab9a1109327..be824287de92db3e29945ac87db7d8d8ab7c3125 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 0040be93d62a74fab1cc15a2f976dd39ae3b784a..3806e974caa18e1fbd6da562277fcb7d4ddd8a7e 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 0000000000000000000000000000000000000000..56879c3d42ff58404911e56b0ed17bb6fb339bd6 --- /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 + +// ************************************************************************* //