xo-gc stack: many small utest improvements.
This commit is contained in:
parent
ff0d256e97
commit
6583fff677
17 changed files with 386 additions and 76 deletions
|
|
@ -10,32 +10,6 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <xo/facet/FacetRegistry.hpp>
|
||||
|
||||
namespace xo {
|
||||
namespace mm {
|
||||
class ACollector;
|
||||
class AGCObject;
|
||||
|
||||
// ----- mm_do_assign -----
|
||||
|
||||
/** gc-aware assignment; engage special book-keeping for cross-gen pointers **/
|
||||
inline void mm_do_assign(obj<ACollector> & gc,
|
||||
void * parent,
|
||||
obj<AGCObject> * p_lhs,
|
||||
obj<AGCObject> & rhs)
|
||||
{
|
||||
if (gc.data()) {
|
||||
gc.assign_member(parent, p_lhs, rhs);
|
||||
} else {
|
||||
// assume null collector downstream from allocator that does not provide collection.
|
||||
// In that no additional assignment work.
|
||||
|
||||
*p_lhs = rhs;
|
||||
}
|
||||
};
|
||||
|
||||
} /*namespace mm*/
|
||||
} /*namespace xo*/
|
||||
//#include <xo/facet/FacetRegistry.hpp>
|
||||
|
||||
/* end RCollector_aux.hpp */
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ set(UTEST_SRCS
|
|||
Generation.test.cpp
|
||||
Role.test.cpp
|
||||
VisitReason.test.cpp
|
||||
ResourceVisitor.test.cpp
|
||||
dp.test.cpp
|
||||
random_allocs.cpp
|
||||
)
|
||||
|
|
|
|||
25
xo-alloc2/utest/ResourceVisitor.test.cpp
Normal file
25
xo-alloc2/utest/ResourceVisitor.test.cpp
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
/** @file ResourceVisitor.test.cpp
|
||||
*
|
||||
* @author Roland Conybeare, May 2026
|
||||
**/
|
||||
|
||||
#include <xo/alloc2/ResourceVisitor.hpp>
|
||||
#include <catch2/catch.hpp>
|
||||
|
||||
namespace xo {
|
||||
using xo::mm::AResourceVisitor;
|
||||
|
||||
namespace ut {
|
||||
|
||||
TEST_CASE("ResourceVisitor-1", "[resourcevisitor]")
|
||||
{
|
||||
obj<AResourceVisitor> v;
|
||||
|
||||
REQUIRE(v.iface());
|
||||
REQUIRE(!v.iface()->_has_null_vptr());
|
||||
}
|
||||
|
||||
}
|
||||
} /*namespace xo*/
|
||||
|
||||
/* end ResourceVisitor.test.cpp */
|
||||
|
|
@ -11,7 +11,7 @@ namespace xo {
|
|||
|
||||
namespace ut {
|
||||
|
||||
TEST_CASE("visitreason-1", "[visitreason]")
|
||||
TEST_CASE("VisitReason-1", "[visitreason]")
|
||||
{
|
||||
REQUIRE(VisitReason::unspecified() == VisitReason::unspecified());
|
||||
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ namespace xo {
|
|||
|
||||
Generation gc_upto() const { return gc_upto_; }
|
||||
|
||||
bool is_idle() const { return mode_ == Mode::idle; }
|
||||
bool is_running() const { return mode_ == Mode::gc; }
|
||||
bool is_verify() const { return mode_ == Mode::verify; }
|
||||
|
||||
|
|
@ -62,7 +63,7 @@ namespace xo {
|
|||
struct GCStatistics {
|
||||
public:
|
||||
GCStatistics() = default;
|
||||
explicit GCStatistics(uint32_t n_gc) : n_gc_{n_gc} {};
|
||||
//explicit GCStatistics(uint32_t n_gc) : n_gc_{n_gc} {};
|
||||
|
||||
uint32_t n_gc() const noexcept { return n_gc_; }
|
||||
|
||||
|
|
|
|||
|
|
@ -195,6 +195,9 @@ namespace xo {
|
|||
void cleanup_phase(Generation upto,
|
||||
bool sanitize_flag);
|
||||
|
||||
/** Revert to empty state **/
|
||||
void clear();
|
||||
|
||||
private:
|
||||
|
||||
/** configure @ref object_types_, using @p page_z **/
|
||||
|
|
|
|||
|
|
@ -84,6 +84,9 @@ namespace xo {
|
|||
void forward_mutation_log(obj<AGCObjectVisitor> gc,
|
||||
Generation upto);
|
||||
|
||||
/** Reset mutation log store to empty state **/
|
||||
void clear();
|
||||
|
||||
private:
|
||||
/** aux init function: create mutation log **/
|
||||
MutationLog _make_mlog(uint32_t igen, char tag_char,
|
||||
|
|
|
|||
|
|
@ -20,9 +20,7 @@ namespace xo {
|
|||
**/
|
||||
struct ObjectTypeSlot {
|
||||
ObjectTypeSlot() {}
|
||||
explicit ObjectTypeSlot(AGCObject * iface) {
|
||||
this->store_iface(iface);
|
||||
}
|
||||
//explicit ObjectTypeSlot(AGCObject * iface) { this->store_iface(iface); }
|
||||
|
||||
/** true iff this slot is empty **/
|
||||
bool is_null() const noexcept {
|
||||
|
|
|
|||
|
|
@ -322,7 +322,7 @@ namespace xo {
|
|||
obj<AAllocator> error_mm,
|
||||
obj<AGCObject> * p_output) const noexcept
|
||||
{
|
||||
return gco_store_.report_object_types(mm, error_mm, p_output);
|
||||
return gco_store_.report_object_ages(mm, error_mm, p_output);
|
||||
}
|
||||
|
||||
size_type
|
||||
|
|
@ -672,15 +672,9 @@ namespace xo {
|
|||
|
||||
void
|
||||
DX1Collector::clear() noexcept {
|
||||
for (Role ri : Role::all()) {
|
||||
for (Generation gj{0}; gj < config_.n_generation_; ++gj) {
|
||||
DArena * arena = this->get_space(ri, gj);
|
||||
|
||||
assert(arena);
|
||||
|
||||
arena->clear();
|
||||
}
|
||||
}
|
||||
mlog_store_.clear();
|
||||
gco_store_.clear();
|
||||
root_set_.clear();
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -1182,6 +1182,21 @@ namespace xo {
|
|||
} while (fixup_work > 0);
|
||||
} /*_forward_children_until_fixpoint*/
|
||||
|
||||
void
|
||||
GCObjectStore::clear()
|
||||
{
|
||||
object_types_.clear();
|
||||
|
||||
for (Role ri : Role::all()) {
|
||||
for (Generation gj{0}; gj < config_.n_generation_; ++gj) {
|
||||
DArena * arena = this->get_space(ri, gj);
|
||||
|
||||
assert(arena);
|
||||
|
||||
arena->clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
} /*namespace mm*/
|
||||
} /*namespace xo*/
|
||||
|
||||
|
|
|
|||
|
|
@ -560,6 +560,20 @@ namespace xo {
|
|||
return counters;
|
||||
}
|
||||
|
||||
void
|
||||
MutationLogStore::clear()
|
||||
{
|
||||
// parallels .init_mlogs(), see also
|
||||
|
||||
for (uint32_t igen = 0, ngen = config_.n_generation_; igen + 1 < ngen; ++igen) {
|
||||
if (igen + 1 < c_max_generation) {
|
||||
for (std::uint32_t mlog_role = 0; mlog_role < c_n_role + 1; ++mlog_role) {
|
||||
this->mlog_storage_[mlog_role][igen].clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} /*namespace mm*/
|
||||
} /*namespace xo*/
|
||||
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ set(UTEST_SRCS
|
|||
GCObjectStore.test.cpp
|
||||
GCObjectConversion.test.cpp
|
||||
Object2.test.cpp
|
||||
ObjectAge.test.cpp
|
||||
|
||||
DMockCollector.cpp
|
||||
ICollector_DMockCollector.cpp
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ namespace xo {
|
|||
using xo::mm::DArena;
|
||||
using xo::mm::DArenaIterator;
|
||||
using xo::mm::X1CollectorConfig;
|
||||
using xo::mm::Generation;
|
||||
using xo::mm::ArenaConfig;
|
||||
using xo::mm::AllocHeaderConfig;
|
||||
using xo::mm::cmpresult;
|
||||
|
|
@ -34,11 +35,16 @@ namespace xo {
|
|||
using std::byte;
|
||||
|
||||
namespace ut {
|
||||
TEST_CASE("DX1CollectorIterator-0", "[alloc2][gc][DX1Collector]")
|
||||
{
|
||||
}
|
||||
|
||||
TEST_CASE("IAllocIterator_Xfer_DX1CollectorIterator", "[alloc2]")
|
||||
{
|
||||
/* verify IAllocIterator_Xfer is constructible + satisfies concept checks */
|
||||
IAllocIterator_Xfer<DX1CollectorIterator, IAllocIterator_DX1CollectorIterator> xfer;
|
||||
REQUIRE(IAllocIterator_Xfer<DX1CollectorIterator, IAllocIterator_DX1CollectorIterator>::_valid);
|
||||
|
||||
}
|
||||
|
||||
TEST_CASE("DX1CollectorIterator-1", "[alloc2][gc][DX1Collector]")
|
||||
|
|
@ -128,10 +134,25 @@ namespace xo {
|
|||
auto ix = gc.begin();
|
||||
auto end_ix = gc.end();
|
||||
|
||||
REQUIRE(ix != DX1CollectorIterator::invalid());
|
||||
REQUIRE(end_ix != DX1CollectorIterator::invalid());
|
||||
|
||||
REQUIRE(ix.is_valid());
|
||||
REQUIRE(end_ix.is_valid());
|
||||
REQUIRE(ix != end_ix);
|
||||
|
||||
REQUIRE(ix.gen_ix() == Generation::g0());
|
||||
REQUIRE(ix.gen_ix() < gc.config_.n_generation_);
|
||||
REQUIRE(ix.gen_hi() == gc.config_.n_generation_);
|
||||
REQUIRE(ix.arena_ix() == gc.to_space(Generation::g0())->begin());
|
||||
REQUIRE(ix.arena_hi() == gc.to_space(Generation::g0())->end());
|
||||
|
||||
{
|
||||
// we have one alloc, so can visit it
|
||||
auto info = *ix;
|
||||
REQUIRE(info.is_valid());
|
||||
}
|
||||
|
||||
/* verify obj 'fat pointer' packaging */
|
||||
auto ix_vt = with_facet<AAllocIterator>::mkobj(&ix);
|
||||
auto end_ix_vt = with_facet<AAllocIterator>::mkobj(&end_ix);
|
||||
|
|
|
|||
|
|
@ -24,9 +24,13 @@ namespace ut {
|
|||
using xo::scm::DInteger;
|
||||
using xo::mm::MutationLogStore;
|
||||
using xo::mm::MutationLogConfig;
|
||||
using xo::mm::MutationLog;
|
||||
using xo::mm::MutationLogEntry;
|
||||
using xo::mm::GCObjectStore;
|
||||
using xo::mm::GCObjectStoreConfig;
|
||||
using xo::mm::DGCObjectStoreVisitor;
|
||||
using xo::mm::Role;
|
||||
using xo::mm::Generation;
|
||||
using xo::mm::DArena;
|
||||
using xo::mm::ArenaConfig;
|
||||
using xo::mm::X1VerifyStats;
|
||||
|
|
@ -434,6 +438,24 @@ namespace ut {
|
|||
//
|
||||
fixture.mls_.init_mlogs(getpagesize());
|
||||
|
||||
{
|
||||
MutationLog * to_0_mlog
|
||||
= fixture.mls_.get_mlog(Role::to_space(),
|
||||
Generation::g0());
|
||||
MutationLog * from_0_mlog
|
||||
= fixture.mls_.get_mlog(Role::from_space(),
|
||||
Generation::g0());
|
||||
MutationLog * triage_0_mlog
|
||||
= fixture.mls_.triage_mlog(Generation::g0());
|
||||
|
||||
REQUIRE(to_0_mlog);
|
||||
REQUIRE(from_0_mlog);
|
||||
REQUIRE(triage_0_mlog);
|
||||
REQUIRE(to_0_mlog != from_0_mlog);
|
||||
REQUIRE(to_0_mlog != triage_0_mlog);
|
||||
REQUIRE(from_0_mlog != triage_0_mlog);
|
||||
}
|
||||
|
||||
{
|
||||
// updates counters in fixture.verify_stats_
|
||||
fixture.gcos_.verify_ok();
|
||||
|
|
@ -454,6 +476,13 @@ namespace ut {
|
|||
GCObjectStore & gcos = fixture.gcos_;
|
||||
MutationLogStore & mls = fixture.mls_;
|
||||
|
||||
{
|
||||
MutationLogEntry mentry;
|
||||
|
||||
REQUIRE(mentry.parent() == nullptr);
|
||||
REQUIRE(mentry.p_data() == nullptr);
|
||||
}
|
||||
|
||||
{
|
||||
// gcos setup. parallels GCObjectStore.test.cpp
|
||||
{
|
||||
|
|
|
|||
34
xo-gc/utest/ObjectAge.test.cpp
Normal file
34
xo-gc/utest/ObjectAge.test.cpp
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
/** @file ObjectAge.test.cpp
|
||||
*
|
||||
* @author Roland Conybeare, May 2026
|
||||
**/
|
||||
|
||||
#include "object_age.hpp"
|
||||
#include <catch2/catch.hpp>
|
||||
|
||||
namespace xo {
|
||||
using xo::mm::object_age;
|
||||
|
||||
namespace ut {
|
||||
|
||||
TEST_CASE("ObjectAge-1", "[ObjectAge]")
|
||||
{
|
||||
REQUIRE(object_age{0} != object_age{1});
|
||||
REQUIRE(object_age{0} < object_age{1});
|
||||
REQUIRE(object_age{1} > object_age{0});
|
||||
|
||||
{
|
||||
bool x = (object_age{0} > object_age{1});
|
||||
REQUIRE(x == false);
|
||||
}
|
||||
|
||||
{
|
||||
bool x = (object_age{1} < object_age{0});
|
||||
REQUIRE(x == false);
|
||||
}
|
||||
}
|
||||
|
||||
} /*namespace ut*/
|
||||
} /*namespace xo*/
|
||||
|
||||
/* end ObjectAge.test.cpp */
|
||||
|
|
@ -15,6 +15,7 @@
|
|||
#include <xo/object2/List.hpp>
|
||||
|
||||
#include <xo/gc/X1Collector.hpp>
|
||||
#include <xo/alloc2/Arena.hpp>
|
||||
//#include <xo/alloc2/Collector.hpp>
|
||||
#include <xo/alloc2/CollectorTypeRegistry.hpp>
|
||||
|
||||
|
|
@ -43,9 +44,14 @@ namespace ut {
|
|||
using xo::mm::AGCObject;
|
||||
using xo::mm::X1CollectorConfig;
|
||||
using xo::mm::DX1Collector;
|
||||
using xo::mm::GCRoot;
|
||||
using xo::mm::GCObjectStore;
|
||||
using xo::mm::GCStatistics;
|
||||
using xo::mm::DArena;
|
||||
using xo::mm::ArenaConfig;
|
||||
using xo::mm::Generation;
|
||||
using xo::mm::c_n_role;
|
||||
using xo::mm::object_age;
|
||||
using xo::mm::Role;
|
||||
using xo::mm::padding;
|
||||
using xo::facet::obj;
|
||||
|
|
@ -59,17 +65,14 @@ namespace ut {
|
|||
|
||||
namespace {
|
||||
struct testcase_x1 {
|
||||
testcase_x1(std::size_t nz,
|
||||
std::size_t tz,
|
||||
testcase_x1(std::size_t gz,
|
||||
std::size_t n_gct,
|
||||
std::size_t t_gct)
|
||||
: nursery_z_{nz},
|
||||
tenured_z_{tz},
|
||||
: generation_z_{gz},
|
||||
incr_gc_threshold_{n_gct},
|
||||
full_gc_threshold_{t_gct} {}
|
||||
|
||||
std::size_t nursery_z_;
|
||||
std::size_t tenured_z_;
|
||||
std::size_t generation_z_;
|
||||
std::size_t incr_gc_threshold_;
|
||||
std::size_t full_gc_threshold_;
|
||||
};
|
||||
|
|
@ -79,13 +82,50 @@ namespace ut {
|
|||
// n_gct: nursery gc threshold
|
||||
// t_gct: tenured gc threshold
|
||||
//
|
||||
// nz tz n_gct t_gct
|
||||
testcase_x1(4096, 8192, 1024, 1024)
|
||||
// gz n_gct t_gct
|
||||
testcase_x1(8192, 1024, 1024)
|
||||
};
|
||||
}
|
||||
|
||||
static InitEvidence s_init = (InitSubsys<S_gc_tag>::require());
|
||||
|
||||
TEST_CASE("x1-config", "[gc][x1]")
|
||||
{
|
||||
// real purpose: ensure s_init survives static linking
|
||||
REQUIRE(s_init.evidence());
|
||||
|
||||
Subsystem::initialize_all();
|
||||
|
||||
constexpr bool c_debug_flag = false;
|
||||
scope log(XO_DEBUG(c_debug_flag), "x1-config test");
|
||||
|
||||
for (std::size_t i_tc = 0, n_tc = s_testcase_v.size(); i_tc < n_tc; ++i_tc) {
|
||||
scope log(XO_DEBUG(false), xtag("i_tc", i_tc));
|
||||
|
||||
const testcase_x1 & tc = s_testcase_v[i_tc];
|
||||
|
||||
X1CollectorConfig cfg{ .name_ = "x1_test",
|
||||
.arena_config_ = ArenaConfig{
|
||||
.size_ = tc.generation_z_,
|
||||
.store_header_flag_ = true},
|
||||
.object_types_z_ = 16384,
|
||||
.gc_trigger_v_{{
|
||||
tc.incr_gc_threshold_,
|
||||
tc.full_gc_threshold_}},
|
||||
.debug_flag_ = c_debug_flag,
|
||||
};
|
||||
|
||||
REQUIRE(cfg.n_generation_ == 2);
|
||||
REQUIRE(cfg.n_survive_threshold_ == 2);
|
||||
REQUIRE(cfg.age2gen(object_age{0}) == Generation::g0());
|
||||
REQUIRE(cfg.age2gen(object_age{1}) == Generation::g0());
|
||||
REQUIRE(cfg.age2gen(object_age{2}) == Generation::g1());
|
||||
REQUIRE(cfg.age2gen(object_age{99}) == Generation::g1());
|
||||
|
||||
REQUIRE(cfg.promotion_threshold(Generation::g1()) == cfg.n_survive_threshold_);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("x1", "[gc][x1]")
|
||||
{
|
||||
// real purpose: ensure s_init survives static linking
|
||||
|
|
@ -108,17 +148,44 @@ namespace ut {
|
|||
|
||||
X1CollectorConfig cfg{ .name_ = "x1_test",
|
||||
.arena_config_ = ArenaConfig{
|
||||
.size_ = tc.tenured_z_,
|
||||
.size_ = tc.generation_z_,
|
||||
.store_header_flag_ = true},
|
||||
.object_types_z_ = 16384,
|
||||
.gc_trigger_v_{{
|
||||
tc.incr_gc_threshold_,
|
||||
tc.full_gc_threshold_}},
|
||||
.debug_flag_ = c_debug_flag,
|
||||
};
|
||||
.sanitize_flag_ = true,
|
||||
.debug_flag_ = c_debug_flag };
|
||||
|
||||
DX1Collector gc(cfg);
|
||||
|
||||
{
|
||||
// X1Collector never uses the null ctor here.
|
||||
// but it relies on DArenaVector<GCRoot>,
|
||||
// which requires it for DArenaVector<GCRoot>::resize()
|
||||
//
|
||||
GCRoot null_root;
|
||||
|
||||
REQUIRE(null_root.root() == nullptr);
|
||||
}
|
||||
|
||||
// secondary allocator for reporting
|
||||
DArena report_arena(ArenaConfig()
|
||||
.with_name("x1_test_report_arena")
|
||||
.with_size(64 * 1024));
|
||||
auto report_mm = obj<AAllocator,DArena>(&report_arena);
|
||||
|
||||
DArena error_arena(ArenaConfig()
|
||||
.with_name("x1_test_error_arena")
|
||||
.with_size(16 * 1024));
|
||||
auto error_mm = obj<AAllocator,DArena>(&error_arena);
|
||||
|
||||
const GCObjectStore * p_gco = nullptr;
|
||||
{
|
||||
const DX1Collector & c_gc = gc;
|
||||
p_gco = &(c_gc.gco_store());
|
||||
}
|
||||
|
||||
CollectorTypeRegistry::instance()
|
||||
.install_types(obj<ACollector,DX1Collector>(&gc));
|
||||
|
||||
|
|
@ -126,7 +193,9 @@ namespace ut {
|
|||
|
||||
/* verify configuration */
|
||||
{
|
||||
REQUIRE(cfg.n_generation_ == 2);
|
||||
REQUIRE(gc.config().arena_config_.size_ == tc.generation_z_);
|
||||
REQUIRE(gc.config().arena_config_.store_header_flag_ == true);
|
||||
REQUIRE(gc.config().n_generation_ == 2);
|
||||
}
|
||||
|
||||
/* verify initial collector state */
|
||||
|
|
@ -148,8 +217,8 @@ namespace ut {
|
|||
const DArena * from_0 = gc.get_space(Role::from_space(), Generation{0});
|
||||
|
||||
REQUIRE(from_0 != nullptr);
|
||||
REQUIRE(from_0->reserved() >= tc.tenured_z_);
|
||||
REQUIRE(from_0->reserved() < tc.tenured_z_ + from_0->page_z_);
|
||||
REQUIRE(from_0->reserved() >= tc.generation_z_);
|
||||
REQUIRE(from_0->reserved() < tc.generation_z_ + from_0->page_z_);
|
||||
REQUIRE(from_0->reserved() % from_0->page_z_ == 0);
|
||||
REQUIRE(from_0->allocated() == 0);
|
||||
|
||||
|
|
@ -203,18 +272,30 @@ namespace ut {
|
|||
ok = c_o.is_type_installed(typeseq::id<DArray>());
|
||||
REQUIRE(ok);
|
||||
|
||||
REQUIRE(gc_o.name() == cfg.name_);
|
||||
// nothing committed yet (?)
|
||||
REQUIRE(gc_o.size() == cfg.object_types_z_);
|
||||
// no-op
|
||||
REQUIRE(gc_o.expand(0));
|
||||
REQUIRE(gc_o.size() == cfg.object_types_z_);
|
||||
|
||||
// x0_o will be added as gc root. x0_o_orig will not
|
||||
auto x0_o = DFloat::box<AGCObject>(gc_o, 3.1415927);
|
||||
auto x0_o_orig = x0_o;
|
||||
c_o.add_gc_root(&x0_o);
|
||||
REQUIRE(to_0->allocated() == sizeof(AllocHeader) + sizeof(DFloat));
|
||||
|
||||
// n1_o will be added as gc root. n1_o_orig will not
|
||||
auto n1_o = DInteger::box<AGCObject>(gc_o, 42);
|
||||
auto n1_o_orig = n1_o;
|
||||
c_o.add_gc_root(&n1_o);
|
||||
|
||||
REQUIRE(to_0->allocated() == (sizeof(AllocHeader) + sizeof(DFloat)
|
||||
+ sizeof(AllocHeader) + sizeof(DInteger)));
|
||||
|
||||
//DList * l0 = DList::list(gc_o, x0_o);
|
||||
//auto l0_o = with_facet<AGCObject>::mkobj(l0);
|
||||
// l0_o will be added as gc root. l0_o_orig will not
|
||||
auto l0_o = ListOps::list(gc_o, x0_o);
|
||||
auto l0_o_orig = l0_o;
|
||||
c_o.add_gc_root(&l0_o);
|
||||
REQUIRE(to_0->allocated() == (sizeof(AllocHeader) + sizeof(DFloat)
|
||||
+ sizeof(AllocHeader) + sizeof(DInteger)
|
||||
|
|
@ -231,11 +312,23 @@ namespace ut {
|
|||
|
||||
/* check alloc info for newly-allocated object */
|
||||
AllocInfo info = gc.alloc_info((std::byte *)x0_o.data());
|
||||
auto float_tseq = typeseq::id<DFloat>();
|
||||
auto x0_alloc_z = gc.header2size(info.header());
|
||||
|
||||
REQUIRE(info.age() == 0);
|
||||
REQUIRE(info.tseq() == typeseq::id<DFloat>().seqno());
|
||||
REQUIRE(info.tseq() == float_tseq.seqno());
|
||||
REQUIRE(info.size() >= sizeof(DFloat));
|
||||
REQUIRE(info.size() < sizeof(DFloat) + padding::c_alloc_alignment);
|
||||
|
||||
REQUIRE(sizeof(DFloat) <= x0_alloc_z);
|
||||
REQUIRE(x0_alloc_z <= sizeof(DFloat) + sizeof(AllocHeader));
|
||||
REQUIRE(0 == gc.header2age(info.header()));
|
||||
|
||||
REQUIRE(float_tseq.seqno() == gc.header2tseq(info.header()));
|
||||
REQUIRE(false == gc.is_forwarding_header(info.header()));
|
||||
|
||||
REQUIRE(gc.lookup_type(float_tseq));
|
||||
REQUIRE(gc.lookup_type(float_tseq)->_typeseq() == float_tseq);
|
||||
}
|
||||
|
||||
{
|
||||
|
|
@ -245,11 +338,23 @@ namespace ut {
|
|||
|
||||
/* check alloc info for newly-allocated object */
|
||||
AllocInfo info = gc.alloc_info((std::byte *)n1_o.data());
|
||||
auto integer_tseq = typeseq::id<DInteger>();
|
||||
auto n1_alloc_z = gc.header2size(info.header());
|
||||
|
||||
REQUIRE(info.age() == 0);
|
||||
REQUIRE(info.tseq() == typeseq::id<DInteger>().seqno());
|
||||
REQUIRE(info.tseq() == integer_tseq.seqno());
|
||||
REQUIRE(info.size() >= sizeof(DInteger));
|
||||
REQUIRE(info.size() < sizeof(DInteger) + padding::c_alloc_alignment);
|
||||
|
||||
REQUIRE(sizeof(DInteger) <= n1_alloc_z);
|
||||
REQUIRE(n1_alloc_z <= sizeof(DInteger) + sizeof(AllocHeader));
|
||||
REQUIRE(0 == gc.header2age(info.header()));
|
||||
|
||||
REQUIRE(integer_tseq.seqno() == gc.header2tseq(info.header()));
|
||||
REQUIRE(false == gc.is_forwarding_header(info.header()));
|
||||
|
||||
REQUIRE(gc.lookup_type(integer_tseq));
|
||||
REQUIRE(gc.lookup_type(integer_tseq)->_typeseq() == integer_tseq);
|
||||
}
|
||||
|
||||
{
|
||||
|
|
@ -259,14 +364,32 @@ namespace ut {
|
|||
|
||||
/* check alloc info for newly-allocated object */
|
||||
AllocInfo info = gc.alloc_info((std::byte *)l0_o.data());
|
||||
auto list_tseq = typeseq::id<DList>();
|
||||
auto l0_alloc_z = gc.header2size(info.header());
|
||||
|
||||
REQUIRE(info.age() == 0);
|
||||
REQUIRE(info.tseq() == typeseq::id<DList>().seqno());
|
||||
REQUIRE(info.tseq() == list_tseq.seqno());
|
||||
REQUIRE(info.size() >= sizeof(DList));
|
||||
REQUIRE(info.size() < sizeof(DList) + padding::c_alloc_alignment);
|
||||
|
||||
REQUIRE(sizeof(DList) <= l0_alloc_z);
|
||||
REQUIRE(l0_alloc_z <= sizeof(DList) + sizeof(AllocHeader));
|
||||
REQUIRE(0 == gc.header2age(info.header()));
|
||||
|
||||
REQUIRE(list_tseq.seqno() == gc.header2tseq(info.header()));
|
||||
REQUIRE(false == gc.is_forwarding_header(info.header()));
|
||||
|
||||
REQUIRE(gc.lookup_type(list_tseq));
|
||||
REQUIRE(gc.lookup_type(list_tseq)->_typeseq() == list_tseq);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
GCStatistics stats = gc.gc_stats();
|
||||
|
||||
REQUIRE(stats.n_gc() == 0);
|
||||
}
|
||||
|
||||
/* no GC roots, so GC is trivial */
|
||||
c_o.request_gc(Generation{1});
|
||||
|
||||
|
|
@ -274,20 +397,54 @@ namespace ut {
|
|||
log && log(xtag("l0_o.data()->head_.data()", l0_o.data()->head_.data()));
|
||||
log && log(xtag("x0_o.data()", x0_o.data()));
|
||||
|
||||
// gcobjectstore is stable
|
||||
REQUIRE(&gc.gco_store() == p_gco);
|
||||
|
||||
REQUIRE(gc.runstate().gc_upto() == Generation::sentinel());
|
||||
REQUIRE(gc.runstate().is_idle());
|
||||
REQUIRE(!gc.runstate().is_running());
|
||||
REQUIRE(!gc.runstate().is_verify());
|
||||
|
||||
{
|
||||
REQUIRE(!gc.contains(Role::from_space(), x0_o.data()));
|
||||
REQUIRE(gc.contains(Role::to_space(), x0_o.data()));
|
||||
REQUIRE(x0_o.data()->value() == 3.1415927);
|
||||
|
||||
// former location of x0_o now in from-space
|
||||
REQUIRE(gc.contains(Role::from_space(), x0_o_orig.data()));
|
||||
REQUIRE(gc.locate_address(x0_o_orig.data()) == -1);
|
||||
}
|
||||
|
||||
{
|
||||
REQUIRE(!gc.contains(Role::from_space(), n1_o.data()));
|
||||
REQUIRE(gc.contains(Role::to_space(), n1_o.data()));
|
||||
REQUIRE(n1_o.data()->value() == 42);
|
||||
|
||||
REQUIRE(gc.contains(Role::from_space(), n1_o_orig.data()));
|
||||
REQUIRE(gc.locate_address(n1_o_orig.data()) == -1);
|
||||
}
|
||||
|
||||
{
|
||||
REQUIRE(!gc.contains(Role::from_space(), l0_o.data()));
|
||||
REQUIRE(gc.contains(Role::to_space(), l0_o.data()));
|
||||
REQUIRE(l0_o.data()->is_empty() == false);
|
||||
|
||||
REQUIRE(gc.contains(Role::from_space(), l0_o_orig.data()));
|
||||
REQUIRE(gc.locate_address(l0_o_orig.data()) == -1);
|
||||
|
||||
REQUIRE((void*)l0_o.data()->head_.data() == (void*)x0_o.data());
|
||||
REQUIRE((void*)l0_o.data()->rest_ == (void*)DList::_nil());
|
||||
}
|
||||
|
||||
{
|
||||
// verify a non-gc-owned address
|
||||
int x = 999;
|
||||
|
||||
REQUIRE(-1 == gc.locate_address(&x));
|
||||
}
|
||||
|
||||
REQUIRE(gc.size_total() == gc.committed());
|
||||
REQUIRE(gc.mutation_log_entries() == 0);
|
||||
|
||||
Generation g0 = Generation::g0();
|
||||
REQUIRE(c_o.committed(g0, Role::to_space()) == to0_commit_z);
|
||||
|
|
@ -295,6 +452,50 @@ namespace ut {
|
|||
REQUIRE(c_o.locate_address(x0_o.data()) >= 0);
|
||||
REQUIRE(c_o.contains(Role::to_space(), x0_o.data()));
|
||||
|
||||
GCStatistics stats = gc.gc_stats();
|
||||
REQUIRE(stats.n_gc() == 1);
|
||||
|
||||
{
|
||||
obj<AGCObject> report;
|
||||
bool ok = c_o.report_statistics(report_mm, error_mm, &report);
|
||||
REQUIRE(ok);
|
||||
REQUIRE(report);
|
||||
|
||||
// TODO: print report, verify output
|
||||
|
||||
report_mm.clear();
|
||||
error_mm.clear();
|
||||
}
|
||||
|
||||
{
|
||||
obj<AGCObject> report;
|
||||
bool ok = c_o.report_object_ages(report_mm, error_mm, &report);
|
||||
REQUIRE(ok);
|
||||
REQUIRE(report);
|
||||
|
||||
// TODO: print report, verify output
|
||||
|
||||
report_mm.clear();
|
||||
error_mm.clear();
|
||||
}
|
||||
|
||||
{
|
||||
obj<AGCObject> report;
|
||||
bool ok = c_o.report_object_types(report_mm, error_mm, &report);
|
||||
REQUIRE(ok);
|
||||
REQUIRE(report);
|
||||
|
||||
// TODO: print report, verify output
|
||||
|
||||
report_mm.clear();
|
||||
error_mm.clear();
|
||||
}
|
||||
|
||||
gc_o.clear();
|
||||
{
|
||||
REQUIRE(gc_o.allocated() == 0);
|
||||
}
|
||||
|
||||
} catch (std::exception & ex) {
|
||||
std::cerr << "caught exception: " << ex.what() << std::endl;
|
||||
REQUIRE(false);
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@ add_definitions(${PROJECT_CXX_FLAGS})
|
|||
xo_add_genfacetimpl(
|
||||
TARGET xo-stringtable2-facetimpl-gcobject-string
|
||||
FACET_PKG xo_alloc2
|
||||
# REPR String
|
||||
INPUT idl/IGCObject_DString.json5
|
||||
)
|
||||
|
||||
|
|
@ -31,7 +30,6 @@ xo_add_genfacetimpl(
|
|||
xo_add_genfacetimpl(
|
||||
TARGET xo-stringtable2-facetimpl-printable-string
|
||||
FACET_PKG xo_printable2
|
||||
# REPR String
|
||||
INPUT idl/IPrintable_DString.json5
|
||||
)
|
||||
|
||||
|
|
@ -41,7 +39,6 @@ xo_add_genfacetimpl(
|
|||
xo_add_genfacetimpl(
|
||||
TARGET xo-stringtable2-facetimpl-gcobject-uniquestring
|
||||
FACET_PKG xo_alloc2
|
||||
# REPR UniqueString
|
||||
INPUT idl/IGCObject_DUniqueString.json5
|
||||
)
|
||||
|
||||
|
|
@ -49,7 +46,6 @@ xo_add_genfacetimpl(
|
|||
xo_add_genfacetimpl(
|
||||
TARGET xo-stringtable2-facetimpl-printable-uniquestring
|
||||
FACET_PKG xo_printable2
|
||||
# REPR UniqueString
|
||||
INPUT idl/IPrintable_DUniqueString.json5
|
||||
)
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue