diff --git a/Src/Base/AMReX_CArena.H b/Src/Base/AMReX_CArena.H index d68285bc878..163039df2ef 100644 --- a/Src/Base/AMReX_CArena.H +++ b/Src/Base/AMReX_CArena.H @@ -5,13 +5,14 @@ #include #include -#include -#include +#include +#include #include #include -#include -#include +#include #include +#include +#include namespace amrex { @@ -57,7 +58,7 @@ public: * Try to shrink in-place */ [[nodiscard]] void* - shrink_in_place (void* pt, std::size_t sz) final; + shrink_in_place (void* pt, std::size_t new_size) final; /** * \brief Free up allocated memory. Merge neighboring free memory chunks @@ -164,15 +165,15 @@ protected: MemStat* m_stat; }; + //! The list of blocks allocated via ::operator new(). + std::vector > m_alloc; + /** * \brief The type of our freelist and blocklist. * We use a set sorted from lo to hi memory addresses. */ using NL = std::set; - //! The list of blocks allocated via ::operator new(). - std::vector > m_alloc; - /** * \brief The free list of allocated but not currently used blocks. * Maintained in lo to hi memory sorted order. @@ -198,6 +199,8 @@ protected: std::mutex carena_mutex; + + friend std::ostream& operator<< (std::ostream& os, const CArena& arena); }; } diff --git a/Src/Base/AMReX_CArena.cpp b/Src/Base/AMReX_CArena.cpp index 6f7979d4750..c47f8f5ed26 100644 --- a/Src/Base/AMReX_CArena.cpp +++ b/Src/Base/AMReX_CArena.cpp @@ -14,6 +14,7 @@ namespace amrex { #include #include +#include namespace amrex { @@ -203,9 +204,61 @@ CArena::alloc_in_place (void* pt, std::size_t szmin, std::size_t szmax) } void* -CArena::shrink_in_place (void* /*pt*/, std::size_t sz) +CArena::shrink_in_place (void* pt, std::size_t new_size) { - return alloc(sz); // xxxxx TODO + if ((pt == nullptr) || (new_size == 0)) { return nullptr; } + + new_size = Arena::align(new_size); + + std::lock_guard lock(carena_mutex); + + auto busy_it = m_busylist.find(Node(pt,nullptr,0)); + if (busy_it == m_busylist.end()) { + amrex::Abort("CArena::shrink_in_place: unknown pointer"); + return nullptr; + } + AMREX_ASSERT(m_freelist.find(*busy_it) == m_freelist.end()); + + auto const old_size = busy_it->size(); + + if (new_size > old_size) { + amrex::Abort("CArena::shrink_in_place: wrong size. Cannot shrink to a larger size."); + return nullptr; + } else if (new_size == old_size) { + return pt; + } else { + auto const leftover_size = old_size - new_size; + + void* pt2 = static_cast(pt) + new_size; + Node new_free_node(pt2, busy_it->owner(), leftover_size); + + void* pt_end = static_cast(pt) + old_size; + auto free_it = m_freelist.find(Node(pt_end,nullptr,0)); + if ((free_it == m_freelist.end()) || ! new_free_node.coalescable(*free_it)) { + m_freelist.insert(free_it, new_free_node); + } else { + auto& node = const_cast(*free_it); + // This is safe because the free list is std::set and the + // modification of `block` does not change the order of elements + // in the container, even though Node's operator< uses block. + node.block(pt2); + node.size(leftover_size + node.size()); + } + + const_cast(*busy_it).size(new_size); + + m_actually_used -= leftover_size; + +#ifdef AMREX_TINY_PROFILING + if (m_do_profiling) { + TinyProfiler::memory_free(old_size, busy_it->mem_stat()); + auto* stat = TinyProfiler::memory_alloc(new_size, m_profiling_stats); + const_cast(*busy_it).mem_stat(stat); + } +#endif + + return pt; + } } void @@ -439,4 +492,43 @@ CArena::PrintUsage (std::ostream& os, std::string const& name, std::string const << m_busylist.size() << " busy blocks, " << m_freelist.size() << " free blocks\n"; } +std::ostream& operator<< (std::ostream& os, const CArena& arena) +{ + os << "CArea:\n" + << " Hunk size: " << arena.m_hunk << "\n" + << " Memory allocated: " << arena.m_used << "\n" + << " Memory actually used: " << arena.m_actually_used << "\n"; + + if (arena.m_alloc.empty()) { + os << " No memory allocations\n"; + } else { + os << " List of memory alloations: (address, size)\n"; + for (auto const& a : arena.m_alloc) { + os << " " << a.first << ", " << a.second << "\n"; + } + } + + if (arena.m_freelist.empty()) { + os << " No free nodes\n"; + } else { + os << " List of free nodes: (address, owner, size)\n"; + for (auto const& a : arena.m_freelist) { + os << " " << a.block() << ", " << a.owner() << ", " + << a.size() << "\n"; + } + } + + if (arena.m_busylist.empty()) { + os << " No busy nodes\n"; + } else { + os << " List of busy nodes: (address, owner, size)\n"; + for (auto const& a : arena.m_busylist) { + os << " " << a.block() << ", " << a.owner() << ", " + << a.size() << "\n"; + } + } + + return os; +} + } diff --git a/Src/LinearSolvers/MLMG/AMReX_MLCGSolver.H b/Src/LinearSolvers/MLMG/AMReX_MLCGSolver.H index 391fe14c0ae..c99d7b319bd 100644 --- a/Src/LinearSolvers/MLMG/AMReX_MLCGSolver.H +++ b/Src/LinearSolvers/MLMG/AMReX_MLCGSolver.H @@ -90,22 +90,18 @@ MLCGSolverT::solve_bicgstab (MF& sol, const MF& rhs, RT eps_rel, RT eps_abs) const int ncomp = sol.nComp(); - const BoxArray& ba = sol.boxArray(); - const DistributionMapping& dm = sol.DistributionMap(); - const auto& factory = sol.Factory(); - - MF ph(ba, dm, ncomp, sol.nGrowVect(), MFInfo(), factory); - MF sh(ba, dm, ncomp, sol.nGrowVect(), MFInfo(), factory); + MF ph = Lp.make(amrlev, mglev, sol.nGrowVect()); + MF sh = Lp.make(amrlev, mglev, sol.nGrowVect()); ph.setVal(RT(0.0)); sh.setVal(RT(0.0)); - MF sorig(ba, dm, ncomp, nghost, MFInfo(), factory); - MF p (ba, dm, ncomp, nghost, MFInfo(), factory); - MF r (ba, dm, ncomp, nghost, MFInfo(), factory); - MF s (ba, dm, ncomp, nghost, MFInfo(), factory); - MF rh (ba, dm, ncomp, nghost, MFInfo(), factory); - MF v (ba, dm, ncomp, nghost, MFInfo(), factory); - MF t (ba, dm, ncomp, nghost, MFInfo(), factory); + MF sorig = Lp.make(amrlev, mglev, nghost); + MF p = Lp.make(amrlev, mglev, nghost); + MF r = Lp.make(amrlev, mglev, nghost); + MF s = Lp.make(amrlev, mglev, nghost); + MF rh = Lp.make(amrlev, mglev, nghost); + MF v = Lp.make(amrlev, mglev, nghost); + MF t = Lp.make(amrlev, mglev, nghost); Lp.correctionResidual(amrlev, mglev, r, sol, rhs, MLLinOpT::BCMode::Homogeneous);