xo-alloc / xo-object: utest coverage + assorted bugfixes
This commit is contained in:
parent
2048de70f3
commit
bd00826448
34 changed files with 1069 additions and 326 deletions
|
|
@ -13,36 +13,19 @@
|
|||
namespace xo {
|
||||
namespace gc {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -56,24 +39,15 @@ 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>
|
||||
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,
|
||||
#ifdef REDLINE_MEMORY
|
||||
rz,
|
||||
#endif
|
||||
z, debug_flag));
|
||||
}
|
||||
|
||||
|
|
@ -97,22 +71,36 @@ namespace xo {
|
|||
ArenaAlloc::capture_object_statistics(capture_phase phase,
|
||||
ObjectStatistics * p_dest) const
|
||||
{
|
||||
scope log(XO_DEBUG(debug_flag_),
|
||||
xtag("name", name_),
|
||||
xtag("capacity", limit_ - lo_),
|
||||
xtag("alloc", free_ptr_ - lo_),
|
||||
xtag("lo", (void*)lo_),
|
||||
xtag("free_ptr", (void*)free_ptr_));
|
||||
|
||||
using xo::reflect::TaggedPtr;
|
||||
|
||||
std::byte * p = lo_;
|
||||
|
||||
while (p < free_ptr_) {
|
||||
Object * obj = reinterpret_cast<Object *>(p);
|
||||
TaggedPtr tp = obj->self_tp();
|
||||
std::size_t z = obj->_shallow_size();
|
||||
Object * obj = reinterpret_cast<Object *>(p);
|
||||
TaggedPtr tp = obj->self_tp();
|
||||
std::size_t z = obj->_shallow_size();
|
||||
std::uint32_t id = tp.td()->id().id();
|
||||
|
||||
log && log(xtag("obj", (void*)obj),
|
||||
xtag("z", z),
|
||||
xtag("typeid", id));
|
||||
|
||||
if (p_dest->per_type_stats_v_.size() < id + 1)
|
||||
p_dest->per_type_stats_v_.resize(id + 1);
|
||||
|
||||
PerObjectTypeStatistics & dest = p_dest->per_type_stats_v_.at(id);
|
||||
|
||||
dest.td_ = tp.td();
|
||||
|
||||
log && log(xtag("td", tp.td()->short_name()));
|
||||
|
||||
switch (phase) {
|
||||
case capture_phase::sab:
|
||||
++dest.scanned_n_;
|
||||
|
|
@ -130,6 +118,11 @@ namespace xo {
|
|||
assert(p == free_ptr_);
|
||||
}
|
||||
|
||||
const std::string &
|
||||
ArenaAlloc::name() const {
|
||||
return name_;
|
||||
}
|
||||
|
||||
std::size_t
|
||||
ArenaAlloc::size() const {
|
||||
return limit_ - lo_;
|
||||
|
|
@ -167,15 +160,17 @@ namespace xo {
|
|||
return free_ptr_ - checkpoint_;
|
||||
}
|
||||
|
||||
bool
|
||||
ArenaAlloc::debug_flag() const
|
||||
{
|
||||
return debug_flag_;
|
||||
}
|
||||
|
||||
void
|
||||
ArenaAlloc::clear()
|
||||
{
|
||||
this->set_free_ptr(lo_);
|
||||
#ifdef REDLINE_MEMORY
|
||||
this->limit_ = hi_ - redline_z_;
|
||||
#else
|
||||
this->limit_ = hi_;
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -204,7 +199,7 @@ namespace xo {
|
|||
|
||||
std::byte * retval = this->free_ptr_;
|
||||
|
||||
log && log(xtag("self", name_), xtag("z0", z0), xtag("+pad", dz), xtag("z1", z1));
|
||||
log && log(xtag("self", name_), xtag("z0", z0), xtag("+pad", dz), xtag("z1", z1), xtag("avail", this->available()));
|
||||
|
||||
if (free_ptr_ + z1 > limit_) {
|
||||
return nullptr;
|
||||
|
|
@ -215,13 +210,6 @@ namespace xo {
|
|||
return retval;
|
||||
}
|
||||
|
||||
#ifdef REDLINE_MEMORY
|
||||
void
|
||||
ArenaAlloc::release_redline_memory() {
|
||||
this->limit_ = this->hi_;
|
||||
}
|
||||
#endif
|
||||
|
||||
} /*namespace gc*/
|
||||
} /*namespace xo*/
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ set(SELF_SRCS
|
|||
ObjectStatistics.cpp
|
||||
Object.cpp
|
||||
Forwarding1.cpp
|
||||
generation.cpp
|
||||
)
|
||||
|
||||
xo_add_shared_library4(${SELF_LIB} ${PROJECT_NAME}Targets ${PROJECT_VERSION} 1 ${SELF_SRCS})
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ namespace xo {
|
|||
void
|
||||
Forwarding1::display(std::ostream & os) const
|
||||
{
|
||||
os << "<fwd" << xtag("dest", (void*)dest_.ptr()) << ">";
|
||||
os << "<fwd" << xtag("dest-td", dest_->self_tp().td()->short_name()) << ">";
|
||||
}
|
||||
|
||||
Object *
|
||||
|
|
|
|||
|
|
@ -175,7 +175,8 @@ namespace xo {
|
|||
GcStatisticsExt retval = GcStatisticsExt(this->native_gc_statistics());
|
||||
|
||||
retval.nursery_z_ = nursery_[role2int(role::to_space)]->size();
|
||||
retval.nursery_before_checkpoint_z_ = nursery_[role2int(role::to_space)]->before_checkpoint();
|
||||
retval.nursery_before_checkpoint_z_ = this->nursery_to()->before_checkpoint();
|
||||
retval.nursery_after_checkpoint_z_ = this->nursery_to()->after_checkpoint();
|
||||
retval.tenured_z_ = tenured_[role2int(role::to_space)]->size();
|
||||
|
||||
return retval;
|
||||
|
|
@ -254,21 +255,9 @@ namespace xo {
|
|||
{
|
||||
std::byte * x = nursery_[role2int(role::to_space)]->alloc(z);
|
||||
|
||||
if (!x) {
|
||||
/* ListAlloc won't fail -- instead will increase heap size */
|
||||
/* ListAlloc won't fail unless we exhaust memory -- 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);
|
||||
}
|
||||
assert(x);
|
||||
|
||||
return x;
|
||||
}
|
||||
|
|
@ -308,18 +297,6 @@ namespace xo {
|
|||
log && log("nursery");
|
||||
|
||||
retval = nursery_[role2int(role::to_space)]->alloc(z);
|
||||
|
||||
if (!retval) {
|
||||
/* nursery space exhausted !? */
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
|
@ -393,14 +370,6 @@ namespace xo {
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef REDLINE_MEMORY
|
||||
void
|
||||
GC::release_redline_memory()
|
||||
{
|
||||
// not supported feature for GC
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
GC::swap_nursery()
|
||||
{
|
||||
|
|
@ -428,40 +397,62 @@ namespace xo {
|
|||
void
|
||||
GC::swap_spaces(generation target)
|
||||
{
|
||||
scope log(XO_DEBUG(this->debug_flag()));
|
||||
scope log(XO_DEBUG(this->debug_flag()), xtag("upto", target));
|
||||
|
||||
// will be copying into the memory regions currently labelled FromSpace
|
||||
|
||||
/* gc will copy some to-be-determined amount in [0..promote_z]
|
||||
from nursery->tenured generation.
|
||||
*/
|
||||
std::size_t promote_z = nursery_[role2int(role::to_space)]->before_checkpoint();
|
||||
std::size_t max_promote_z = nursery_[role2int(role::to_space)]->before_checkpoint();
|
||||
|
||||
log && log(xtag("max_promote_z", max_promote_z));
|
||||
|
||||
if (target == generation::tenured) {
|
||||
/* gc on tenured generation may need this much space */
|
||||
std::size_t tenured_z = (tenured_[role2int(role::to_space)]->allocated()
|
||||
+ promote_z
|
||||
+ full_gc_threshold_);
|
||||
std::size_t need_tenured_z = (tenured_[role2int(role::to_space)]->allocated()
|
||||
+ max_promote_z
|
||||
+ full_gc_threshold_);
|
||||
|
||||
tenured_[role2int(role::from_space)]->reset(tenured_z);
|
||||
log && log("need_tenured_z", need_tenured_z);
|
||||
|
||||
tenured_from()->reset(need_tenured_z);
|
||||
|
||||
this->swap_tenured();
|
||||
} else {
|
||||
if (tenured_[role2int(role::to_space)]->available() < promote_z) {
|
||||
tenured_[role2int(role::to_space)]->expand(promote_z);
|
||||
std::size_t avail_tenured_z = tenured_[role2int(role::to_space)]->available();
|
||||
|
||||
log && log(xtag("avail_tenured_z", avail_tenured_z));
|
||||
|
||||
if (avail_tenured_z < max_promote_z) {
|
||||
ListAlloc * tenured_to = this->tenured_to();
|
||||
|
||||
tenured_to->expand(max_promote_z, tenured_to->name() + "+");
|
||||
}
|
||||
}
|
||||
|
||||
nursery_[role2int(role::from_space)]->reset(nursery_[role2int(role::to_space)]->allocated()
|
||||
- promote_z
|
||||
+ incr_gc_threshold_);
|
||||
/* subtracting max_promote_z is correct here, since anything not promoted is garbage */
|
||||
std::size_t need_nursery_z = (nursery(role::to_space)->allocated()
|
||||
- max_promote_z
|
||||
+ incr_gc_threshold_);
|
||||
|
||||
log && log(xtag("need_nursery_z", need_nursery_z));
|
||||
|
||||
/* (from-space is about to become to-space, to receive surviving nursery objects) */
|
||||
nursery(role::from_space)->reset(need_nursery_z);
|
||||
|
||||
this->swap_nursery();
|
||||
|
||||
this->swap_mutation_log();
|
||||
|
||||
log && log(xtag("nursery.from", nursery_[role2int(role::from_space)]->name()));
|
||||
log && log(xtag("nursery.to", nursery_[role2int(role::to_space) ]->name()));
|
||||
log && log(xtag("tenured.from", tenured_[role2int(role::from_space)]->name()));
|
||||
log && log(xtag("tenured.to", tenured_[role2int(role::to_space) ]->name()));
|
||||
ListAlloc * N_from = nursery(role::from_space);
|
||||
log && log(xtag("nursery.from", N_from->name()), xtag("size", N_from->size()));
|
||||
ListAlloc * N_to = nursery(role::to_space);
|
||||
log && log(xtag("nursery.to", N_to->name()), xtag("size", N_to->size()));
|
||||
ListAlloc * T_from = tenured(role::from_space);
|
||||
log && log(xtag("tenured.from", T_from->name()), xtag("size", T_from->size()));
|
||||
ListAlloc * T_to = tenured(role::to_space);
|
||||
log && log(xtag("tenured.to", T_to->name()), xtag("size", T_to->size()));
|
||||
|
||||
} /*swap_spaces*/
|
||||
|
||||
|
|
@ -504,8 +495,12 @@ namespace xo {
|
|||
void
|
||||
GC::copy_globals(generation upto)
|
||||
{
|
||||
scope log(XO_DEBUG(config_.debug_flag_),
|
||||
xtag("roots", gc_root_v_.size()));
|
||||
|
||||
for (Object ** pp_root : gc_root_v_) {
|
||||
this->copy_object(pp_root, upto, &object_statistics_sae_[gen2int(upto)]);
|
||||
this->copy_object(pp_root, upto,
|
||||
&object_statistics_sae_[gen2int(upto)]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -750,28 +745,30 @@ namespace xo {
|
|||
{
|
||||
scope log(XO_DEBUG(config_.debug_flag_));
|
||||
|
||||
std::size_t N_allocated = nursery_[role2int(role::from_space)]->after_checkpoint();
|
||||
std::size_t T_allocated = tenured_[role2int(role::from_space)]->after_checkpoint();
|
||||
std::size_t N_allocated = nursery_from()->after_checkpoint();
|
||||
std::size_t T_allocated = tenured_from()->after_checkpoint();
|
||||
|
||||
std::size_t N_before_gc = nursery_[role2int(role::from_space)]->allocated();
|
||||
std::size_t T_before_gc = tenured_[role2int(role::from_space)]->allocated();
|
||||
std::size_t N_before_gc = nursery_from()->allocated();
|
||||
std::size_t T_before_gc = tenured_from()->allocated();
|
||||
|
||||
std::size_t N_after_gc = nursery_[role2int(role::to_space)]->allocated();
|
||||
std::size_t T_after_gc = tenured_[role2int(role::to_space)]->allocated();
|
||||
std::size_t N_after_gc = nursery_to()->allocated();
|
||||
std::size_t T_after_gc = tenured_to()->allocated();
|
||||
//std::byte * N_free_ptr = nursery_[role2int(role::to_space)]->free_ptr();
|
||||
|
||||
std::size_t promote_z = gc_statistics_.total_promoted_ - gc_statistics_.total_promoted_sab_;
|
||||
std::size_t promote_z = (gc_statistics_.total_promoted_
|
||||
- gc_statistics_.total_promoted_sab_);
|
||||
|
||||
this->nursery_[role2int(role::from_space)]->reset(0);
|
||||
this->tenured_[role2int(role::from_space)]->reset(0);
|
||||
/* Don't reset from-space here, it's unnecessary.
|
||||
* Would be permissible, but interferes with GC object modelling in
|
||||
* xo-object/utest/GC.test.cpp
|
||||
*/
|
||||
//this->nursery_[role2int(role::from_space)]->reset(0);
|
||||
//this->tenured_[role2int(role::from_space)]->reset(0);
|
||||
|
||||
/* objects currenty in to-space nursery have survived one collection */
|
||||
this->nursery_[role2int(role::to_space)]->checkpoint();
|
||||
|
||||
// nursery_[role2int(role::to_space)]->set_redline(nursery_[role2int(role::to_space)]->allocated() + incr_gc_threshold_)
|
||||
|
||||
this->nursery_to()->checkpoint();
|
||||
if (upto == generation::tenured)
|
||||
this->tenured_[role2int(role::to_space)]->checkpoint();
|
||||
this->tenured_to()->checkpoint();
|
||||
|
||||
if (log) {
|
||||
log(xtag("N_allocated", N_allocated));
|
||||
|
|
@ -819,7 +816,7 @@ namespace xo {
|
|||
|
||||
this->capture_object_statistics(upto, capture_phase::sab);
|
||||
|
||||
log && log("step 1 : swap to/from roles");
|
||||
log && log("step 1 : swap to/from roles");
|
||||
|
||||
this->swap_spaces(upto);
|
||||
|
||||
|
|
@ -829,15 +826,15 @@ namespace xo {
|
|||
|
||||
log && log("step 2b: TODO: copy pinned");
|
||||
|
||||
log && log("step 3 : forward mutation log");
|
||||
log && log("step 3 : forward mutation log");
|
||||
|
||||
this->forward_mutation_log(upto);
|
||||
|
||||
log && log("step 4 : TODO: notify destructor log");
|
||||
log && log("step 4 : TODO: notify destructor log");
|
||||
|
||||
log && log("step 5 : TODO: keep reachable weak pointers");
|
||||
log && log("step 5 : TODO: keep reachable weak pointers");
|
||||
|
||||
log && log("step 6 : cleanup");
|
||||
log && log("step 6 : cleanup");
|
||||
|
||||
this->cleanup_phase(upto);
|
||||
|
||||
|
|
|
|||
|
|
@ -32,12 +32,12 @@ namespace xo {
|
|||
PerGenerationStatistics::display(std::ostream & os) const
|
||||
{
|
||||
os << "<PerGenerationStatistics"
|
||||
<< rtag("used", used_z_)
|
||||
<< rtag("n_gc", n_gc_)
|
||||
<< rtag("new_alloc_z", new_alloc_z_)
|
||||
<< rtag("scanned_z", scanned_z_)
|
||||
<< rtag("survive_z", survive_z_)
|
||||
<< rtag("promote_z", promote_z_)
|
||||
<< xrtag("used", used_z_)
|
||||
<< xrtag("n_gc", n_gc_)
|
||||
<< xrtag("new_alloc_z", new_alloc_z_)
|
||||
<< xrtag("scanned_z", scanned_z_)
|
||||
<< xrtag("survive_z", survive_z_)
|
||||
<< xrtag("promote_z", promote_z_)
|
||||
<< ">";
|
||||
}
|
||||
|
||||
|
|
@ -62,9 +62,9 @@ namespace xo {
|
|||
GcStatistics::display(std::ostream & os) const
|
||||
{
|
||||
os << "<GcStatistics"
|
||||
<< rtag("gen_v", gen_v_)
|
||||
<< rtag("total_allocated", total_allocated_)
|
||||
<< rtag("total_promoted_sab", total_promoted_sab_)
|
||||
<< xrtag("gen_v", gen_v_)
|
||||
<< xrtag("total_allocated", total_allocated_)
|
||||
<< xrtag("total_promoted_sab", total_promoted_sab_)
|
||||
// total_promoted
|
||||
// n_mtuation
|
||||
// n_logged_mutation
|
||||
|
|
@ -78,17 +78,17 @@ namespace xo {
|
|||
GcStatisticsExt::display(std::ostream & os) const
|
||||
{
|
||||
os << "<GcStatisticsExt"
|
||||
<< rtag("gen_v", gen_v_)
|
||||
<< rtag("total_allocated", total_allocated_)
|
||||
<< rtag("total_promoted_sab", total_promoted_)
|
||||
<< rtag("nursery_z", nursery_z_)
|
||||
<< rtag("nursery_before_ckp_z", nursery_before_checkpoint_z_)
|
||||
<< rtag("nursery_after_ckp_z", nursery_after_checkpoint_z_)
|
||||
<< rtag("tenured_z", tenured_z_)
|
||||
<< rtag("n_mutation", n_mutation_)
|
||||
<< rtag("n_logged_mutation", n_logged_mutation_)
|
||||
<< rtag("n_xgen_mutation", n_xgen_mutation_)
|
||||
<< rtag("n_xkcp_mutation", n_xckp_mutation_)
|
||||
<< xrtag("gen_v", gen_v_)
|
||||
<< xrtag("total_allocated", total_allocated_)
|
||||
<< xrtag("total_promoted_sab", total_promoted_)
|
||||
<< xrtag("nursery_z", nursery_z_)
|
||||
<< xrtag("nursery_before_ckp_z", nursery_before_checkpoint_z_)
|
||||
<< xrtag("nursery_after_ckp_z", nursery_after_checkpoint_z_)
|
||||
<< xrtag("tenured_z", tenured_z_)
|
||||
<< xrtag("n_mutation", n_mutation_)
|
||||
<< xrtag("n_logged_mutation", n_logged_mutation_)
|
||||
<< xrtag("n_xgen_mutation", n_xgen_mutation_)
|
||||
<< xrtag("n_xckp_mutation", n_xckp_mutation_)
|
||||
// << xtag("per_type_stats", per_type_stats_)
|
||||
<< ">";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
#include "ListAlloc.hpp"
|
||||
#include "ArenaAlloc.hpp"
|
||||
#include "xo/indentlog/scope.hpp"
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
|
||||
|
|
@ -13,9 +14,6 @@ namespace xo {
|
|||
ListAlloc::ListAlloc(std::unique_ptr<ArenaAlloc> 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)},
|
||||
|
|
@ -24,9 +22,6 @@ namespace xo {
|
|||
current_z_{cz},
|
||||
next_z_{nz},
|
||||
total_z_{tz},
|
||||
#ifdef REDLINE_MEMOORY
|
||||
use_redline_{use_redline},
|
||||
#endif
|
||||
debug_flag_{debug_flag}
|
||||
{}
|
||||
|
||||
|
|
@ -39,9 +34,6 @@ namespace xo {
|
|||
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,
|
||||
#ifdef REDLINE_MEMORY
|
||||
0,
|
||||
#endif
|
||||
cz, debug_flag)};
|
||||
|
||||
if (!hd)
|
||||
|
|
@ -52,9 +44,6 @@ namespace xo {
|
|||
up<ListAlloc> retval{new ListAlloc(std::move(hd),
|
||||
marked,
|
||||
cz, nz, cz,
|
||||
#ifdef REDLINE_MEMORY
|
||||
false /*!use_redline*/,
|
||||
#endif
|
||||
debug_flag)};
|
||||
|
||||
return retval;
|
||||
|
|
@ -134,34 +123,31 @@ namespace xo {
|
|||
bool
|
||||
ListAlloc::is_before_checkpoint(const void * x) const {
|
||||
if (!marked_)
|
||||
return false;
|
||||
return true;
|
||||
|
||||
if ((marked_ == hd_.get()) && hd_->contains(x))
|
||||
return hd_->is_before_checkpoint(x);
|
||||
if (marked_ && marked_->contains(x))
|
||||
return marked_->is_before_checkpoint(x);
|
||||
|
||||
/*
|
||||
* 1. allocs in full_l_ appear in youngest-to-oldest order
|
||||
* 2. allocators that appear before marked_ in full_l_ count as 'after checkpoint'
|
||||
* 3. allocators that appear after marked_ in full_l_ count as 'before checkpoint'
|
||||
* 1. allocs in full_l_ appear in oldest-to-youngest order
|
||||
* 2. allocators that appear before marked_ in full_l_ count as 'before checkpoint'
|
||||
* 3. allocators that appear after marked_ in full_l_ count as 'after checkpoint'
|
||||
*/
|
||||
|
||||
bool younger_than_marked = true;
|
||||
bool older_than_marked = true;
|
||||
|
||||
for (const auto & alloc : full_l_) {
|
||||
if (younger_than_marked) {
|
||||
if (older_than_marked) {
|
||||
if (alloc.get() == marked_) {
|
||||
/* nothing else to test on this iteration,
|
||||
* already checked .marked_ specifically
|
||||
*/
|
||||
younger_than_marked = false;
|
||||
break;
|
||||
} else {
|
||||
/* after checkpoint */
|
||||
/* before checkpoint */
|
||||
if (alloc->contains(x))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
if (alloc->contains(x))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -171,55 +157,63 @@ namespace xo {
|
|||
std::size_t
|
||||
ListAlloc::before_checkpoint() const
|
||||
{
|
||||
scope log(XO_DEBUG(false && debug_flag_), xtag("marked", marked_ ? marked_->name() : ""));
|
||||
|
||||
if (marked_) {
|
||||
if (full_l_.empty()) {
|
||||
assert(marked_ == hd_.get());
|
||||
|
||||
return marked_->before_checkpoint();
|
||||
} else {
|
||||
std::size_t z = 0;
|
||||
|
||||
/* control here: .marked & .full_l non-empty. */
|
||||
if (hd_.get() == marked_) {
|
||||
z += hd_->before_checkpoint();
|
||||
|
||||
/* anything in .full_l is older than marked .hd */
|
||||
for (const auto & alloc : full_l_) {
|
||||
z += alloc->allocated();
|
||||
}
|
||||
|
||||
return z;
|
||||
} else {
|
||||
/* messiest case: .marked is true,
|
||||
* and not the youngest arena
|
||||
*/
|
||||
|
||||
/* full_l always in increasing time order: oldest-to-youngest order */
|
||||
size_t i_alloc = 0;
|
||||
for (const auto & alloc : full_l_) {
|
||||
log && log(xtag("i_alloc", i_alloc),
|
||||
xtag("alloc", alloc->name()),
|
||||
xtag("z", z));
|
||||
|
||||
if (alloc.get() == marked_) {
|
||||
log && log("marked", xtag("+z", marked_->before_checkpoint()));
|
||||
z += marked_->before_checkpoint();
|
||||
break;
|
||||
} else {
|
||||
log && log("older than marked", xtag("+z", alloc->allocated()));
|
||||
z += alloc->allocated();
|
||||
}
|
||||
++i_alloc;
|
||||
}
|
||||
}
|
||||
|
||||
return z;
|
||||
}
|
||||
} else {
|
||||
/* count everything allocated */
|
||||
/* count *everything* allocated */
|
||||
return this->allocated();
|
||||
}
|
||||
|
||||
std::size_t z = 0;
|
||||
|
||||
/* control here: .marked & .full_l non-empty. */
|
||||
if (hd_.get() == marked_) {
|
||||
z += hd_->before_checkpoint();
|
||||
|
||||
/* anything in .full_l older than marked .hd */
|
||||
for (const auto & alloc : full_l_) {
|
||||
z += alloc->allocated();
|
||||
}
|
||||
|
||||
return z;
|
||||
} else {
|
||||
/* messiest case: .marked is true,
|
||||
* and not the youngest arena
|
||||
*/
|
||||
bool younger_than_marked = true;
|
||||
|
||||
for (const auto & alloc : full_l_) {
|
||||
if (younger_than_marked) {
|
||||
if (alloc.get() == marked_) {
|
||||
younger_than_marked = false;
|
||||
z += marked_->before_checkpoint();
|
||||
} else {
|
||||
;
|
||||
}
|
||||
} else {
|
||||
z += alloc->allocated();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return z;
|
||||
}
|
||||
|
||||
std::size_t
|
||||
ListAlloc::after_checkpoint() const
|
||||
{
|
||||
scope log(XO_DEBUG(false && debug_flag_), xtag("marked", marked_ ? marked_->name() : ""));
|
||||
|
||||
if (!marked_)
|
||||
return 0;
|
||||
|
||||
|
|
@ -229,25 +223,44 @@ namespace xo {
|
|||
return marked_->after_checkpoint();
|
||||
}
|
||||
|
||||
bool younger_than_marked = true;
|
||||
bool older_than_marked = true;
|
||||
|
||||
std::size_t z = 0;
|
||||
|
||||
std::size_t i_alloc = 0;
|
||||
for (const auto & alloc : full_l_) {
|
||||
if (younger_than_marked) {
|
||||
log && log(xtag("i_alloc", i_alloc),
|
||||
xtag("alloc", alloc->name()),
|
||||
xtag("z", z));
|
||||
|
||||
if (older_than_marked) {
|
||||
if (alloc.get() == marked_) {
|
||||
younger_than_marked = false;
|
||||
log && log("marked", xtag("+z", marked_->after_checkpoint()));
|
||||
older_than_marked = false;
|
||||
z += marked_->after_checkpoint();
|
||||
break;
|
||||
} else {
|
||||
z += alloc->allocated();
|
||||
}
|
||||
} else {
|
||||
/* younger than marked */
|
||||
log && log("younger", xtag("+z", alloc->allocated()));
|
||||
z += alloc->allocated();
|
||||
}
|
||||
|
||||
++i_alloc;
|
||||
}
|
||||
|
||||
/** head must be included, since it's always the youngest bucket **/
|
||||
z += hd_->after_checkpoint();
|
||||
|
||||
log && log("z", z);
|
||||
|
||||
return z;
|
||||
}
|
||||
|
||||
bool
|
||||
ListAlloc::debug_flag() const {
|
||||
return debug_flag_;
|
||||
}
|
||||
|
||||
void
|
||||
ListAlloc::clear() {
|
||||
// general hygiene
|
||||
|
|
@ -258,26 +271,17 @@ 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
|
||||
scope log(XO_DEBUG(debug_flag_), xtag("z", z));
|
||||
|
||||
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();
|
||||
|
|
@ -285,16 +289,22 @@ namespace xo {
|
|||
|
||||
return true;
|
||||
} else {
|
||||
std::string old_name = this->hd_->name();
|
||||
|
||||
this->hd_.reset(nullptr);
|
||||
this->total_z_ = 0;
|
||||
|
||||
return this->expand(z);
|
||||
return this->expand(z, old_name + "+");
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
ListAlloc::expand(std::size_t z)
|
||||
ListAlloc::expand(std::size_t z, const std::string & name)
|
||||
{
|
||||
scope log(XO_DEBUG(debug_flag_), xtag("name", name));
|
||||
|
||||
//log && log("before", xtag("before_ckp", this->before_checkpoint()));
|
||||
|
||||
std::size_t cz = current_z_;
|
||||
std::size_t nz = next_z_;
|
||||
std::size_t tz;
|
||||
|
|
@ -305,12 +315,9 @@ namespace xo {
|
|||
nz = tz;
|
||||
} while (cz < z);
|
||||
|
||||
std::string name = hd_->name() + "+exp";
|
||||
log && log("expand to", xtag("cz", cz));
|
||||
|
||||
std::unique_ptr<ArenaAlloc> new_alloc = ArenaAlloc::make(name,
|
||||
#ifdef REDLINE_MEMORY
|
||||
0,
|
||||
#endif
|
||||
cz, debug_flag_);
|
||||
|
||||
if (!new_alloc)
|
||||
|
|
@ -320,41 +327,43 @@ namespace xo {
|
|||
this->next_z_ = nz;
|
||||
this->total_z_ += cz;
|
||||
|
||||
if (hd_)
|
||||
this->full_l_.push_back(std::move(hd_));
|
||||
|
||||
this->hd_ = std::move(new_alloc);
|
||||
|
||||
//log && log("after", xtag("before_ckp", this->before_checkpoint()));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
ListAlloc::checkpoint() {
|
||||
scope log(XO_DEBUG(debug_flag_));
|
||||
|
||||
hd_->checkpoint();
|
||||
|
||||
this->marked_ = hd_.get();
|
||||
|
||||
log && log(xtag("hd", (void*)hd_.get()), xtag("marked", (void*)marked_));
|
||||
}
|
||||
|
||||
std::byte *
|
||||
ListAlloc::alloc(std::size_t z) {
|
||||
scope log(XO_DEBUG(debug_flag_));
|
||||
|
||||
std::byte * retval = hd_->alloc(z);
|
||||
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
if (this->expand(z))
|
||||
log && log("space exhausted -> expand");
|
||||
|
||||
if (this->expand(z, hd_->name() + "+"))
|
||||
return hd_->alloc(z);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
#ifdef REDLINE_MEMORY
|
||||
void
|
||||
ListAlloc::release_redline_memory()
|
||||
{
|
||||
if (use_redline_)
|
||||
redlined_flag_ = true;
|
||||
|
||||
this->hd_->release_redline_memory();
|
||||
}
|
||||
#endif
|
||||
} /*namespace gc*/
|
||||
} /*namespace xo*/
|
||||
|
||||
|
|
|
|||
|
|
@ -14,13 +14,13 @@ namespace xo {
|
|||
{
|
||||
os << "<PerObjectTypeStatistics";
|
||||
if (td_)
|
||||
os << rtag("td", td_->short_name());
|
||||
os << xrtag("td", td_->short_name());
|
||||
else
|
||||
os << rtag("td", "nullptr");
|
||||
os << rtag("scanned_n", scanned_n_)
|
||||
<< rtag("scanned_z", scanned_z_)
|
||||
<< rtag("survive_n", survive_n_)
|
||||
<< rtag("survive_z", survive_z_)
|
||||
os << xrtag("td", "nullptr");
|
||||
os << xrtag("scanned_n", scanned_n_)
|
||||
<< xrtag("scanned_z", scanned_z_)
|
||||
<< xrtag("survive_n", survive_n_)
|
||||
<< xrtag("survive_z", survive_z_)
|
||||
<< ">";
|
||||
}
|
||||
|
||||
|
|
|
|||
22
xo-alloc/src/alloc/generation.cpp
Normal file
22
xo-alloc/src/alloc/generation.cpp
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
/* generation.cpp
|
||||
*
|
||||
* author: Roland Conybeare, Aug 2025
|
||||
*/
|
||||
|
||||
#include "generation.hpp"
|
||||
|
||||
namespace xo {
|
||||
namespace gc {
|
||||
const char * gen2str(generation x) {
|
||||
switch (x) {
|
||||
case generation::nursery: return "nursery";
|
||||
case generation::tenured: return "tenured";
|
||||
case generation::N: break;
|
||||
}
|
||||
return "?generation";
|
||||
}
|
||||
|
||||
} /*namespace gc*/
|
||||
} /*namespace xo*/
|
||||
|
||||
/* generation.cpp */
|
||||
Loading…
Add table
Add a link
Reference in a new issue