From 8b622e69995fb58f40d38931412fb4332e102b01 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Wed, 6 Aug 2025 22:50:29 -0500 Subject: [PATCH] xo-alloc: retire redline-memory feature --- include/xo/alloc/ArenaAlloc.hpp | 12 +++++++++- include/xo/alloc/GC.hpp | 2 ++ include/xo/alloc/IAlloc.hpp | 2 ++ include/xo/alloc/ListAlloc.hpp | 13 +++++++++-- src/alloc/ArenaAlloc.cpp | 39 ++++++++++++++++++++++++++++++--- src/alloc/GC.cpp | 8 +++++++ src/alloc/ListAlloc.cpp | 26 ++++++++++++++++++++-- utest/ArenaAlloc.test.cpp | 14 ++++++++++-- 8 files changed, 106 insertions(+), 10 deletions(-) diff --git a/include/xo/alloc/ArenaAlloc.hpp b/include/xo/alloc/ArenaAlloc.hpp index 9f41a8f1..51b72c9e 100644 --- a/include/xo/alloc/ArenaAlloc.hpp +++ b/include/xo/alloc/ArenaAlloc.hpp @@ -42,7 +42,9 @@ namespace xo { * with reserved capacity @p redline_z. **/ static up make(const std::string & name, +#ifdef REDLINE_MEMORY std::size_t redline_z, +#endif std::size_t z, bool debug_flag); @@ -66,10 +68,16 @@ namespace xo { virtual void clear() final override; virtual void checkpoint() final override; virtual std::byte * alloc(std::size_t z) final override; +#ifdef REDLINE_MEMORY virtual void release_redline_memory() final override; +#endif private: - ArenaAlloc(const std::string & name, std::size_t rz, std::size_t z, bool debug_flag); + ArenaAlloc(const std::string & name, +#ifdef REDLINE_MEMORY + std::size_t rz, +#endif + std::size_t z, bool debug_flag); private: /** @@ -91,8 +99,10 @@ namespace xo { std::byte * free_ptr_ = nullptr; /** soft limit: end of released memory **/ std::byte * limit_ = nullptr; +#ifdef REDLINE_MEMORY /** amount of last-resort memory to reserve **/ std::size_t redline_z_ = 0; +#endif /** hard limit: end of allocated memory **/ std::byte * hi_ = nullptr; /** true to enable detailed debug logging **/ diff --git a/include/xo/alloc/GC.hpp b/include/xo/alloc/GC.hpp index daef1881..679e5286 100644 --- a/include/xo/alloc/GC.hpp +++ b/include/xo/alloc/GC.hpp @@ -194,7 +194,9 @@ namespace xo { virtual std::byte * alloc(std::size_t z) final override; virtual std::byte * alloc_gc_copy(std::size_t z, const void * src) final override; +#ifdef REDLINE_MEMORY virtual void release_redline_memory() final override; +#endif private: /** begin GC now **/ diff --git a/include/xo/alloc/IAlloc.hpp b/include/xo/alloc/IAlloc.hpp index 272fe9ad..2eacd9cc 100644 --- a/include/xo/alloc/IAlloc.hpp +++ b/include/xo/alloc/IAlloc.hpp @@ -76,8 +76,10 @@ namespace xo { * Only used in @ref GC. Default implementation asserts and returns nullptr **/ virtual std::byte * alloc_gc_copy(std::size_t z, const void * src); +#ifdef REDLINE_MEMORY /** release last-resort reserved memory **/ virtual void release_redline_memory() = 0; +#endif }; } /*namespace gc*/ diff --git a/include/xo/alloc/ListAlloc.hpp b/include/xo/alloc/ListAlloc.hpp index f9c20d00..627bbf50 100644 --- a/include/xo/alloc/ListAlloc.hpp +++ b/include/xo/alloc/ListAlloc.hpp @@ -29,7 +29,9 @@ namespace xo { ListAlloc(std::unique_ptr hd, ArenaAlloc * marked, std::size_t cz, std::size_t nz, std::size_t tz, +#ifdef REDLINE_MEMORY bool use_redline, +#endif bool debug_flag); ~ListAlloc(); @@ -66,7 +68,9 @@ namespace xo { virtual void clear() final override; virtual void checkpoint() final override; virtual std::byte * alloc(std::size_t z) final override; +#ifdef REDLINE_MEMORY virtual void release_redline_memory() final override; +#endif private: /** **/ @@ -79,11 +83,16 @@ namespace xo { * from trying to converge on app working set size **/ std::list> full_l_; - std::size_t current_z_ = 0;; - std::size_t next_z_ = 0;; + /** size of current arena @ref hd_ **/ + std::size_t current_z_ = 0; + /** if @ref hd_ fills, size of next arena to allocate **/ + std::size_t next_z_ = 0; + /** total size of @ref hd_ + contents of @ref full_l_ **/ std::size_t total_z_ = 0; +#ifdef REDLINE_MEMORY bool use_redline_ = false; bool redlined_flag_ = false; +#endif /** true to enable debug logging **/ bool debug_flag_ = false; diff --git a/src/alloc/ArenaAlloc.cpp b/src/alloc/ArenaAlloc.cpp index ae67365a..94053560 100644 --- a/src/alloc/ArenaAlloc.cpp +++ b/src/alloc/ArenaAlloc.cpp @@ -12,20 +12,37 @@ namespace xo { namespace gc { - ArenaAlloc::ArenaAlloc(const std::string & name, std::size_t rz, std::size_t z, bool debug_flag) + ArenaAlloc::ArenaAlloc(const std::string & name, +#ifdef REDLINE_MEMORY + std::size_t rz, +#endif + std::size_t z, bool debug_flag) { this->name_ = name; +#ifdef REDLINE_MEMORY this->lo_ = (new std::byte [rz + z]); +#else + this->lo_ = (new std::byte [z]); +#endif this->checkpoint_ = lo_; this->free_ptr_ = lo_; this->limit_ = lo_ + z; +#ifdef REDLINE_MEMORY this->redline_z_ = rz; this->hi_ = limit_ + rz; +#else + this->hi_ = limit_; +#endif this->debug_flag_ = debug_flag; if (!lo_) { +#ifdef REDLINE_MEMORY throw std::runtime_error(tostr("ArenaAlloc: allocation failed", xtag("size", rz + z))); +#else + throw std::runtime_error(tostr("ArenaAlloc: allocation failed", + xtag("size", z))); +#endif } } @@ -39,15 +56,25 @@ namespace xo { this->checkpoint_ = nullptr; this->free_ptr_ = nullptr; this->limit_ = nullptr; +#ifdef REDLINE_MEMORY this->redline_z_ = 0; +#endif this->hi_ = nullptr; this->debug_flag_ = false; } up - ArenaAlloc::make(const std::string & name, std::size_t rz, std::size_t z, bool debug_flag) + ArenaAlloc::make(const std::string & name, +#ifdef REDLINE_MEMORY + std::size_t rz, +#endif + std::size_t z, bool debug_flag) { - return up(new ArenaAlloc(name, rz, z, debug_flag)); + return up(new ArenaAlloc(name, +#ifdef REDLINE_MEMORY + rz, +#endif + z, debug_flag)); } void @@ -144,7 +171,11 @@ namespace xo { ArenaAlloc::clear() { this->set_free_ptr(lo_); +#ifdef REDLINE_MEMORY this->limit_ = hi_ - redline_z_; +#else + this->limit_ = hi_; +#endif } void @@ -184,10 +215,12 @@ namespace xo { return retval; } +#ifdef REDLINE_MEMORY void ArenaAlloc::release_redline_memory() { this->limit_ = this->hi_; } +#endif } /*namespace gc*/ } /*namespace xo*/ diff --git a/src/alloc/GC.cpp b/src/alloc/GC.cpp index afac26df..460ac770 100644 --- a/src/alloc/GC.cpp +++ b/src/alloc/GC.cpp @@ -255,13 +255,17 @@ namespace xo { std::byte * x = nursery_[role2int(role::to_space)]->alloc(z); if (!x) { + /* ListAlloc won't fail -- instead will increase heap size */ + this->request_gc(generation::nursery); +#ifdef REDLINE_MEMORY if (incr_gc_pending_ || full_gc_pending_) nursery_[role2int(role::to_space)]->release_redline_memory(); /* try (just once) more, maybe request fits in redline space */ x = nursery_[role2int(role::to_space)]->alloc(z); +#endif assert(x); } @@ -310,7 +314,9 @@ namespace xo { this->request_gc(generation::nursery); +#ifdef REDLINE_MEMORY nursery_[role2int(role::to_space)]->release_redline_memory(); +#endif retval = nursery_[role2int(role::to_space)]->alloc(z); } @@ -387,11 +393,13 @@ namespace xo { } } +#ifdef REDLINE_MEMORY void GC::release_redline_memory() { // not supported feature for GC } +#endif void GC::swap_nursery() diff --git a/src/alloc/ListAlloc.cpp b/src/alloc/ListAlloc.cpp index 9d727591..1f84d5c6 100644 --- a/src/alloc/ListAlloc.cpp +++ b/src/alloc/ListAlloc.cpp @@ -13,7 +13,9 @@ namespace xo { ListAlloc::ListAlloc(std::unique_ptr hd, ArenaAlloc * marked, std::size_t cz, std::size_t nz, std::size_t tz, +#ifdef REDLINE_MEMORY bool use_redline, +#endif bool debug_flag) : start_z_{cz}, hd_{std::move(hd)}, @@ -22,7 +24,9 @@ namespace xo { current_z_{cz}, next_z_{nz}, total_z_{tz}, +#ifdef REDLINE_MEMOORY use_redline_{use_redline}, +#endif debug_flag_{debug_flag} {} @@ -34,7 +38,11 @@ namespace xo { up ListAlloc::make(const std::string & name, std::size_t cz, std::size_t nz, bool debug_flag) { - std::unique_ptr hd{ArenaAlloc::make(name, 0, cz, debug_flag)}; + std::unique_ptr hd{ArenaAlloc::make(name, +#ifdef REDLINE_MEMORY + 0, +#endif + cz, debug_flag)}; if (!hd) return nullptr; @@ -44,7 +52,9 @@ namespace xo { up retval{new ListAlloc(std::move(hd), marked, cz, nz, cz, +#ifdef REDLINE_MEMORY false /*!use_redline*/, +#endif debug_flag)}; return retval; @@ -248,20 +258,26 @@ namespace xo { current_z_ = 0; next_z_ = 0; total_z_ = 0; +#ifdef REDLINE_MEMORY use_redline_ = false; +#endif } bool ListAlloc::reset(std::size_t z) { +#ifdef REDLINE_MEMORY // warning: hd_->size() does not include redline memory hd_->release_redline_memory(); +#endif bool recycle_head_bucket = hd_ && (z <= hd_->size()); this->full_l_.clear(); this->marked_ = nullptr; +#ifdef REDLINE_MEMORY this->redlined_flag_ = false; +#endif if (recycle_head_bucket) { this->hd_->clear(); @@ -291,7 +307,11 @@ namespace xo { std::string name = hd_->name() + "+exp"; - std::unique_ptr new_alloc = ArenaAlloc::make(name, 0, cz, debug_flag_); + std::unique_ptr new_alloc = ArenaAlloc::make(name, +#ifdef REDLINE_MEMORY + 0, +#endif + cz, debug_flag_); if (!new_alloc) return false; @@ -325,6 +345,7 @@ namespace xo { return nullptr; } +#ifdef REDLINE_MEMORY void ListAlloc::release_redline_memory() { @@ -333,6 +354,7 @@ namespace xo { this->hd_->release_redline_memory(); } +#endif } /*namespace gc*/ } /*namespace xo*/ diff --git a/utest/ArenaAlloc.test.cpp b/utest/ArenaAlloc.test.cpp index aae2695b..0e4582e9 100644 --- a/utest/ArenaAlloc.test.cpp +++ b/utest/ArenaAlloc.test.cpp @@ -14,9 +14,15 @@ namespace xo { namespace { struct testcase_alloc { testcase_alloc(std::size_t rz, std::size_t z) - : redline_z_{rz}, arena_z_{z} {} + : +#ifdef REDLINE_MEMORY + redline_z_{rz}, +#endif + arena_z_{z} {} +#ifdef REDLINE_MEMORY std::size_t redline_z_; +#endif std::size_t arena_z_; }; @@ -35,7 +41,11 @@ namespace xo { constexpr bool c_debug_flag = false; - auto alloc = ArenaAlloc::make("linearalloc", tc.redline_z_, tc.arena_z_, c_debug_flag); + auto alloc = ArenaAlloc::make("linearalloc", +#ifdef REDLINE_MEMORY + tc.redline_z_, +#endif + tc.arena_z_, c_debug_flag); REQUIRE(alloc.get()); REQUIRE(alloc->name() == "linearalloc");