xo-alloc: utest: fix broken alloc utests

This commit is contained in:
Roland Conybeare 2025-11-15 16:38:18 -05:00
commit 1c97e2aa93
5 changed files with 82 additions and 40 deletions

View file

@ -168,6 +168,12 @@ namespace xo {
bool is_full_gc_pending() const { return full_gc_pending_; }
/** true during (and only during) a GC cycle **/
bool gc_in_progress() const { return runstate_.in_progress(); }
/** @return pagesize (will be the same for {nursery, tenured} spaces) **/
std::size_t pagesize() const;
/** @return allocation portion of Nursery to-space **/
std::size_t nursery_to_allocated() const;
/** @return reserved size of Nursery to-space **/
std::size_t nursery_to_reserved() const;
/** @return committed size of Nursery to-space **/

View file

@ -14,7 +14,9 @@ set(SELF_SRCS
)
xo_add_shared_library4(${SELF_LIB} ${PROJECT_NAME}Targets ${PROJECT_VERSION} 1 ${SELF_SRCS})
# xo-unit used for time measurement
xo_dependency(${SELF_LIB} xo_unit)
xo_dependency(${SELF_LIB} indentlog)
xo_dependency(${SELF_LIB} reflect)
xo_dependency(${SELF_LIB} callback)

View file

@ -201,12 +201,24 @@ namespace xo {
return retval;
}
std::size_t
GC::pagesize() const
{
return nursery_to()->page_size();
}
std::size_t
GC::nursery_from_allocated() const
{
return nursery_from()->allocated();
}
std::size_t
GC::nursery_to_allocated() const
{
return nursery_to()->allocated();
}
std::size_t
GC::nursery_to_reserved() const
{

View file

@ -1,4 +1,4 @@
# build unittest alloc/utest
# xo-alloc/utest/CMakeLists.txt
#
# NOTE: more GC tests in xo-object/utest
@ -16,6 +16,11 @@ set(UTEST_SRCS
generation.test.cpp
)
xo_add_utest_executable(${UTEST_EXE} ${UTEST_SRCS})
xo_self_dependency(${UTEST_EXE} xo_alloc)
xo_external_target_dependency(${UTEST_EXE} Catch2 Catch2::Catch2)
if (ENABLE_TESTING)
xo_add_utest_executable(${UTEST_EXE} ${UTEST_SRCS})
xo_self_dependency(${UTEST_EXE} xo_alloc)
xo_dependency(${UTEST_EXE} reflect)
xo_external_target_dependency(${UTEST_EXE} Catch2 Catch2::Catch2)
endif()
# end CmakeLists.txt

View file

@ -15,55 +15,72 @@ namespace xo {
namespace {
struct testcase_gc {
testcase_gc(std::size_t nz, std::size_t tz) : nursery_z_{nz}, tenured_z_{tz} {}
testcase_gc(std::size_t nz, std::size_t tz, std::size_t n_gct, std::size_t t_gct)
: nursery_z_{nz}, tenured_z_{tz}, incr_gc_threshold_{n_gct}, full_gc_threshold_{t_gct} {}
std::size_t nursery_z_;
std::size_t tenured_z_;
std::size_t incr_gc_threshold_;
std::size_t full_gc_threshold_;
};
std::vector<testcase_gc>
s_testcase_v = {
testcase_gc(1024, 4096)
// nz tz n_gct t_gct
testcase_gc(1024, 4096, 1024, 4096)
};
}
TEST_CASE("gc", "[alloc][gc]")
{
for (std::size_t i_tc = 0, n_tc = s_testcase_v.size(); i_tc < n_tc; ++i_tc) {
const testcase_gc & tc = s_testcase_v[i_tc];
try {
const testcase_gc & tc = s_testcase_v[i_tc];
up<GC> gc = GC::make(
{.initial_nursery_z_ = tc.nursery_z_,
.initial_tenured_z_ = tc.tenured_z_});
up<GC> gc = GC::make(
{.initial_nursery_z_ = tc.nursery_z_,
.initial_tenured_z_ = tc.tenured_z_,
.incr_gc_threshold_ = tc.incr_gc_threshold_,
.full_gc_threshold_ = tc.full_gc_threshold_,
});
REQUIRE(gc.get());
REQUIRE(gc->name() == "GC");
REQUIRE(gc->size() == tc.nursery_z_ + tc.tenured_z_);
REQUIRE(gc->allocated() == 0);
REQUIRE(gc->available() == tc.nursery_z_);
REQUIRE(gc->before_checkpoint() == 0);
// ListAlloc model is that nothing is before checkpoint
// until it's first established
REQUIRE(gc->after_checkpoint() == 0);
REQUIRE(gc.get());
REQUIRE(gc->name() == "GC");
REQUIRE(gc->nursery_to_allocated() == 0);
REQUIRE(gc->nursery_to_committed() >= tc.nursery_z_);
REQUIRE(gc->nursery_to_reserved() >= tc.nursery_z_);
REQUIRE(gc->nursery_to_reserved() < tc.nursery_z_ + gc->pagesize());
REQUIRE(gc->size() >= tc.nursery_z_ + tc.tenured_z_);
REQUIRE(gc->size() < tc.nursery_z_ + gc->pagesize() + tc.tenured_z_ + gc->pagesize());
REQUIRE(gc->allocated() == 0);
REQUIRE(gc->available() == gc->nursery_to_reserved());
REQUIRE(gc->before_checkpoint() == 0);
// ListAlloc model is that nothing is before checkpoint
// until it's first established
REQUIRE(gc->after_checkpoint() == 0);
REQUIRE(gc->gc_in_progress() == false);
REQUIRE(gc->is_gc_enabled() == true);
REQUIRE(gc->native_gc_statistics().gen_v_[gen2int(generation::nursery)].n_gc_ == 0);
REQUIRE(gc->native_gc_statistics().gen_v_[gen2int(generation::tenured)].n_gc_ == 0);
REQUIRE(gc->gc_in_progress() == false);
REQUIRE(gc->is_gc_enabled() == true);
REQUIRE(gc->native_gc_statistics().gen_v_[gen2int(generation::nursery)].n_gc_ == 0);
REQUIRE(gc->native_gc_statistics().gen_v_[gen2int(generation::tenured)].n_gc_ == 0);
/* gc with empty state */
gc->request_gc(generation::nursery);
/* gc with empty state */
gc->request_gc(generation::nursery);
REQUIRE(gc->gc_in_progress() == false);
REQUIRE(gc->native_gc_statistics().gen_v_[gen2int(generation::nursery)].n_gc_ == 1);
REQUIRE(gc->native_gc_statistics().gen_v_[gen2int(generation::tenured)].n_gc_ == 0);
REQUIRE(gc->gc_in_progress() == false);
REQUIRE(gc->native_gc_statistics().gen_v_[gen2int(generation::nursery)].n_gc_ == 1);
REQUIRE(gc->native_gc_statistics().gen_v_[gen2int(generation::tenured)].n_gc_ == 0);
/* still empty state */
gc->request_gc(generation::tenured);
/* still empty state */
gc->request_gc(generation::tenured);
REQUIRE(gc->gc_in_progress() == false);
REQUIRE(gc->native_gc_statistics().gen_v_[gen2int(generation::nursery)].n_gc_ == 1);
REQUIRE(gc->native_gc_statistics().gen_v_[gen2int(generation::tenured)].n_gc_ == 1);
REQUIRE(gc->gc_in_progress() == false);
REQUIRE(gc->native_gc_statistics().gen_v_[gen2int(generation::nursery)].n_gc_ == 1);
REQUIRE(gc->native_gc_statistics().gen_v_[gen2int(generation::tenured)].n_gc_ == 1);
} catch (std::exception &ex) {
std::cerr << "caught exception: " << ex.what() << std::endl;
REQUIRE(false);
}
}
}