xo-alloc: retire redline-memory feature

This commit is contained in:
Roland Conybeare 2025-08-06 22:50:29 -05:00
commit 2048de70f3
9 changed files with 111 additions and 11 deletions

View file

@ -42,7 +42,9 @@ namespace xo {
* with reserved capacity @p redline_z. * with reserved capacity @p redline_z.
**/ **/
static up<ArenaAlloc> make(const std::string & name, static up<ArenaAlloc> make(const std::string & name,
#ifdef REDLINE_MEMORY
std::size_t redline_z, std::size_t redline_z,
#endif
std::size_t z, std::size_t z,
bool debug_flag); bool debug_flag);
@ -66,10 +68,16 @@ namespace xo {
virtual void clear() final override; virtual void clear() final override;
virtual void checkpoint() final override; virtual void checkpoint() final override;
virtual std::byte * alloc(std::size_t z) final override; virtual std::byte * alloc(std::size_t z) final override;
#ifdef REDLINE_MEMORY
virtual void release_redline_memory() final override; virtual void release_redline_memory() final override;
#endif
private: 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: private:
/** /**
@ -91,8 +99,10 @@ namespace xo {
std::byte * free_ptr_ = nullptr; std::byte * free_ptr_ = nullptr;
/** soft limit: end of released memory **/ /** soft limit: end of released memory **/
std::byte * limit_ = nullptr; std::byte * limit_ = nullptr;
#ifdef REDLINE_MEMORY
/** amount of last-resort memory to reserve **/ /** amount of last-resort memory to reserve **/
std::size_t redline_z_ = 0; std::size_t redline_z_ = 0;
#endif
/** hard limit: end of allocated memory **/ /** hard limit: end of allocated memory **/
std::byte * hi_ = nullptr; std::byte * hi_ = nullptr;
/** true to enable detailed debug logging **/ /** true to enable detailed debug logging **/

View file

@ -194,7 +194,9 @@ namespace xo {
virtual std::byte * alloc(std::size_t z) final override; 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; 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; virtual void release_redline_memory() final override;
#endif
private: private:
/** begin GC now **/ /** begin GC now **/

View file

@ -76,8 +76,10 @@ namespace xo {
* Only used in @ref GC. Default implementation asserts and returns nullptr * Only used in @ref GC. Default implementation asserts and returns nullptr
**/ **/
virtual std::byte * alloc_gc_copy(std::size_t z, const void * src); virtual std::byte * alloc_gc_copy(std::size_t z, const void * src);
#ifdef REDLINE_MEMORY
/** release last-resort reserved memory **/ /** release last-resort reserved memory **/
virtual void release_redline_memory() = 0; virtual void release_redline_memory() = 0;
#endif
}; };
} /*namespace gc*/ } /*namespace gc*/

View file

@ -29,7 +29,9 @@ namespace xo {
ListAlloc(std::unique_ptr<ArenaAlloc> hd, ListAlloc(std::unique_ptr<ArenaAlloc> hd,
ArenaAlloc * marked, ArenaAlloc * marked,
std::size_t cz, std::size_t nz, std::size_t tz, std::size_t cz, std::size_t nz, std::size_t tz,
#ifdef REDLINE_MEMORY
bool use_redline, bool use_redline,
#endif
bool debug_flag); bool debug_flag);
~ListAlloc(); ~ListAlloc();
@ -66,7 +68,9 @@ namespace xo {
virtual void clear() final override; virtual void clear() final override;
virtual void checkpoint() final override; virtual void checkpoint() final override;
virtual std::byte * alloc(std::size_t z) final override; virtual std::byte * alloc(std::size_t z) final override;
#ifdef REDLINE_MEMORY
virtual void release_redline_memory() final override; virtual void release_redline_memory() final override;
#endif
private: private:
/** **/ /** **/
@ -79,11 +83,16 @@ namespace xo {
* from trying to converge on app working set size * from trying to converge on app working set size
**/ **/
std::list<std::unique_ptr<ArenaAlloc>> full_l_; std::list<std::unique_ptr<ArenaAlloc>> full_l_;
std::size_t current_z_ = 0;; /** size of current arena @ref hd_ **/
std::size_t next_z_ = 0;; 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; std::size_t total_z_ = 0;
#ifdef REDLINE_MEMORY
bool use_redline_ = false; bool use_redline_ = false;
bool redlined_flag_ = false; bool redlined_flag_ = false;
#endif
/** true to enable debug logging **/ /** true to enable debug logging **/
bool debug_flag_ = false; bool debug_flag_ = false;

View file

@ -12,20 +12,37 @@
namespace xo { namespace xo {
namespace gc { 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; this->name_ = name;
#ifdef REDLINE_MEMORY
this->lo_ = (new std::byte [rz + z]); this->lo_ = (new std::byte [rz + z]);
#else
this->lo_ = (new std::byte [z]);
#endif
this->checkpoint_ = lo_; this->checkpoint_ = lo_;
this->free_ptr_ = lo_; this->free_ptr_ = lo_;
this->limit_ = lo_ + z; this->limit_ = lo_ + z;
#ifdef REDLINE_MEMORY
this->redline_z_ = rz; this->redline_z_ = rz;
this->hi_ = limit_ + rz; this->hi_ = limit_ + rz;
#else
this->hi_ = limit_;
#endif
this->debug_flag_ = debug_flag; this->debug_flag_ = debug_flag;
if (!lo_) { if (!lo_) {
#ifdef REDLINE_MEMORY
throw std::runtime_error(tostr("ArenaAlloc: allocation failed", throw std::runtime_error(tostr("ArenaAlloc: allocation failed",
xtag("size", rz + z))); 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->checkpoint_ = nullptr;
this->free_ptr_ = nullptr; this->free_ptr_ = nullptr;
this->limit_ = nullptr; this->limit_ = nullptr;
#ifdef REDLINE_MEMORY
this->redline_z_ = 0; this->redline_z_ = 0;
#endif
this->hi_ = nullptr; this->hi_ = nullptr;
this->debug_flag_ = false; this->debug_flag_ = false;
} }
up<ArenaAlloc> up<ArenaAlloc>
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<ArenaAlloc>(new ArenaAlloc(name, rz, z, debug_flag)); return up<ArenaAlloc>(new ArenaAlloc(name,
#ifdef REDLINE_MEMORY
rz,
#endif
z, debug_flag));
} }
void void
@ -144,7 +171,11 @@ namespace xo {
ArenaAlloc::clear() ArenaAlloc::clear()
{ {
this->set_free_ptr(lo_); this->set_free_ptr(lo_);
#ifdef REDLINE_MEMORY
this->limit_ = hi_ - redline_z_; this->limit_ = hi_ - redline_z_;
#else
this->limit_ = hi_;
#endif
} }
void void
@ -184,10 +215,12 @@ namespace xo {
return retval; return retval;
} }
#ifdef REDLINE_MEMORY
void void
ArenaAlloc::release_redline_memory() { ArenaAlloc::release_redline_memory() {
this->limit_ = this->hi_; this->limit_ = this->hi_;
} }
#endif
} /*namespace gc*/ } /*namespace gc*/
} /*namespace xo*/ } /*namespace xo*/

View file

@ -255,13 +255,17 @@ namespace xo {
std::byte * x = nursery_[role2int(role::to_space)]->alloc(z); std::byte * x = nursery_[role2int(role::to_space)]->alloc(z);
if (!x) { if (!x) {
/* ListAlloc won't fail -- instead will increase heap size */
this->request_gc(generation::nursery); this->request_gc(generation::nursery);
#ifdef REDLINE_MEMORY
if (incr_gc_pending_ || full_gc_pending_) if (incr_gc_pending_ || full_gc_pending_)
nursery_[role2int(role::to_space)]->release_redline_memory(); nursery_[role2int(role::to_space)]->release_redline_memory();
/* try (just once) more, maybe request fits in redline space */ /* try (just once) more, maybe request fits in redline space */
x = nursery_[role2int(role::to_space)]->alloc(z); x = nursery_[role2int(role::to_space)]->alloc(z);
#endif
assert(x); assert(x);
} }
@ -310,7 +314,9 @@ namespace xo {
this->request_gc(generation::nursery); this->request_gc(generation::nursery);
#ifdef REDLINE_MEMORY
nursery_[role2int(role::to_space)]->release_redline_memory(); nursery_[role2int(role::to_space)]->release_redline_memory();
#endif
retval = nursery_[role2int(role::to_space)]->alloc(z); retval = nursery_[role2int(role::to_space)]->alloc(z);
} }
@ -387,11 +393,13 @@ namespace xo {
} }
} }
#ifdef REDLINE_MEMORY
void void
GC::release_redline_memory() GC::release_redline_memory()
{ {
// not supported feature for GC // not supported feature for GC
} }
#endif
void void
GC::swap_nursery() GC::swap_nursery()

View file

@ -13,7 +13,9 @@ namespace xo {
ListAlloc::ListAlloc(std::unique_ptr<ArenaAlloc> hd, ListAlloc::ListAlloc(std::unique_ptr<ArenaAlloc> hd,
ArenaAlloc * marked, ArenaAlloc * marked,
std::size_t cz, std::size_t nz, std::size_t tz, std::size_t cz, std::size_t nz, std::size_t tz,
#ifdef REDLINE_MEMORY
bool use_redline, bool use_redline,
#endif
bool debug_flag) bool debug_flag)
: start_z_{cz}, : start_z_{cz},
hd_{std::move(hd)}, hd_{std::move(hd)},
@ -22,7 +24,9 @@ namespace xo {
current_z_{cz}, current_z_{cz},
next_z_{nz}, next_z_{nz},
total_z_{tz}, total_z_{tz},
#ifdef REDLINE_MEMOORY
use_redline_{use_redline}, use_redline_{use_redline},
#endif
debug_flag_{debug_flag} debug_flag_{debug_flag}
{} {}
@ -34,7 +38,11 @@ namespace xo {
up<ListAlloc> up<ListAlloc>
ListAlloc::make(const std::string & name, std::size_t cz, std::size_t nz, bool debug_flag) ListAlloc::make(const std::string & name, std::size_t cz, std::size_t nz, bool debug_flag)
{ {
std::unique_ptr<ArenaAlloc> hd{ArenaAlloc::make(name, 0, cz, debug_flag)}; std::unique_ptr<ArenaAlloc> hd{ArenaAlloc::make(name,
#ifdef REDLINE_MEMORY
0,
#endif
cz, debug_flag)};
if (!hd) if (!hd)
return nullptr; return nullptr;
@ -44,7 +52,9 @@ namespace xo {
up<ListAlloc> retval{new ListAlloc(std::move(hd), up<ListAlloc> retval{new ListAlloc(std::move(hd),
marked, marked,
cz, nz, cz, cz, nz, cz,
#ifdef REDLINE_MEMORY
false /*!use_redline*/, false /*!use_redline*/,
#endif
debug_flag)}; debug_flag)};
return retval; return retval;
@ -248,20 +258,26 @@ namespace xo {
current_z_ = 0; current_z_ = 0;
next_z_ = 0; next_z_ = 0;
total_z_ = 0; total_z_ = 0;
#ifdef REDLINE_MEMORY
use_redline_ = false; use_redline_ = false;
#endif
} }
bool bool
ListAlloc::reset(std::size_t z) ListAlloc::reset(std::size_t z)
{ {
#ifdef REDLINE_MEMORY
// warning: hd_->size() does not include redline memory // warning: hd_->size() does not include redline memory
hd_->release_redline_memory(); hd_->release_redline_memory();
#endif
bool recycle_head_bucket = hd_ && (z <= hd_->size()); bool recycle_head_bucket = hd_ && (z <= hd_->size());
this->full_l_.clear(); this->full_l_.clear();
this->marked_ = nullptr; this->marked_ = nullptr;
#ifdef REDLINE_MEMORY
this->redlined_flag_ = false; this->redlined_flag_ = false;
#endif
if (recycle_head_bucket) { if (recycle_head_bucket) {
this->hd_->clear(); this->hd_->clear();
@ -291,7 +307,11 @@ namespace xo {
std::string name = hd_->name() + "+exp"; std::string name = hd_->name() + "+exp";
std::unique_ptr<ArenaAlloc> new_alloc = ArenaAlloc::make(name, 0, cz, debug_flag_); std::unique_ptr<ArenaAlloc> new_alloc = ArenaAlloc::make(name,
#ifdef REDLINE_MEMORY
0,
#endif
cz, debug_flag_);
if (!new_alloc) if (!new_alloc)
return false; return false;
@ -325,6 +345,7 @@ namespace xo {
return nullptr; return nullptr;
} }
#ifdef REDLINE_MEMORY
void void
ListAlloc::release_redline_memory() ListAlloc::release_redline_memory()
{ {
@ -333,6 +354,7 @@ namespace xo {
this->hd_->release_redline_memory(); this->hd_->release_redline_memory();
} }
#endif
} /*namespace gc*/ } /*namespace gc*/
} /*namespace xo*/ } /*namespace xo*/

View file

@ -14,9 +14,15 @@ namespace xo {
namespace { namespace {
struct testcase_alloc { struct testcase_alloc {
testcase_alloc(std::size_t rz, std::size_t z) 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_; std::size_t redline_z_;
#endif
std::size_t arena_z_; std::size_t arena_z_;
}; };
@ -35,7 +41,11 @@ namespace xo {
constexpr bool c_debug_flag = false; 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.get());
REQUIRE(alloc->name() == "linearalloc"); REQUIRE(alloc->name() == "linearalloc");

View file

@ -156,7 +156,11 @@ namespace xo {
TEST_CASE("String.append", "[String]") TEST_CASE("String.append", "[String]")
{ {
const bool c_debug_flag = false; const bool c_debug_flag = false;
up<ArenaAlloc> arena = ArenaAlloc::make("testarena", 0, 16*1024, c_debug_flag); up<ArenaAlloc> arena = ArenaAlloc::make("testarena",
#ifdef REDLINE_MEMORY
0,
#endif
16*1024, c_debug_flag);
Object::mm = arena.get(); Object::mm = arena.get();