xo-gc: refactor, focus on DX1Collector+MutationLogState
This commit is contained in:
parent
9f87d453d0
commit
ae9e97acc2
12 changed files with 140 additions and 57 deletions
|
|
@ -161,6 +161,8 @@ namespace xo {
|
|||
// ----- access methods -----
|
||||
|
||||
const X1CollectorConfig & config() const noexcept { return config_; }
|
||||
const GCObjectStore & gco_store() const noexcept { return gco_store_; }
|
||||
|
||||
std::string_view name() const noexcept { return config_.name_; }
|
||||
GCRunState runstate() const noexcept { return runstate_; }
|
||||
const ObjectTypeTable * get_object_types() const noexcept { return &object_types_; }
|
||||
|
|
|
|||
|
|
@ -5,11 +5,11 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "GCObjectStoreConfig.hpp"
|
||||
#include "generation.hpp"
|
||||
#include "object_age.hpp"
|
||||
#include <xo/alloc2/role.hpp>
|
||||
#include <xo/arena/DArena.hpp>
|
||||
#include <xo/arena/ArenaConfig.hpp>
|
||||
//#include <xo/arena/ArenaConfig.hpp>
|
||||
#include <array>
|
||||
|
||||
namespace xo {
|
||||
|
|
@ -24,7 +24,7 @@ namespace xo {
|
|||
using size_type = DArena::size_type;
|
||||
|
||||
public:
|
||||
GCObjectStore(const ArenaConfig & arena_cfg, uint32_t ngen, bool debug_flag);
|
||||
explicit GCObjectStore(const GCObjectStoreConfig & cfg);
|
||||
|
||||
const DArena * get_space(role r, Generation g) const noexcept { return space_[r][g]; }
|
||||
DArena * get_space(role r, Generation g) noexcept { return space_[r][g]; }
|
||||
|
|
@ -70,19 +70,8 @@ namespace xo {
|
|||
void _init_space();
|
||||
|
||||
private:
|
||||
/** Configuration for collector spaces.
|
||||
* Will have (2 x G) of these,
|
||||
* where G is @ref n_generation_.
|
||||
* Not using name_ member.
|
||||
*
|
||||
* REQUIRE:
|
||||
* - arena_config_.store_header_flag_ must be true
|
||||
**/
|
||||
ArenaConfig arena_config_;
|
||||
/** number of generations in use. Same as @ref X1CollectorConfig::n_generation_ **/
|
||||
uint32_t n_generation_ = 0;
|
||||
/** true to enable debug logging **/
|
||||
bool debug_flag_ = false;
|
||||
/** configuration for gc-aware object store **/
|
||||
GCObjectStoreConfig config_;
|
||||
|
||||
/** arena objects for collector managed memory
|
||||
* 1:1 with roles, but polarity reverses for each collection
|
||||
|
|
|
|||
39
include/xo/gc/GCObjectStoreConfig.hpp
Normal file
39
include/xo/gc/GCObjectStoreConfig.hpp
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
/** @file GCObjectStoreConfig.hpp
|
||||
*
|
||||
* @author Roland Conybeare, Apr 2026
|
||||
**/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <xo/arena/DArena.hpp>
|
||||
|
||||
namespace xo {
|
||||
namespace mm {
|
||||
|
||||
/** @brief record GCObjectStore configuration **/
|
||||
class GCObjectStoreConfig {
|
||||
public:
|
||||
GCObjectStoreConfig(const ArenaConfig & arena_cfg,
|
||||
std::uint32_t ngen,
|
||||
bool debug_flag);
|
||||
|
||||
public:
|
||||
/** Configuration for collector spaces.
|
||||
* Will have (2 x G) of these,
|
||||
* where G is @ref n_generation_.
|
||||
* Not using name_ member.
|
||||
*
|
||||
* REQUIRE:
|
||||
* - arena_config_.store_header_flag_ must be true
|
||||
**/
|
||||
ArenaConfig arena_config_;
|
||||
/** number of generations in use. Same as @ref X1CollectorConfig::n_generation_ **/
|
||||
std::uint32_t n_generation_ = 0;
|
||||
/** true to enable debug logging **/
|
||||
bool debug_flag_ = false;
|
||||
};
|
||||
|
||||
} /*namespace mm*/
|
||||
} /*namespace xo*/
|
||||
|
||||
/* end GCObjectStoreConfig.hpp */
|
||||
|
|
@ -5,24 +5,44 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "generation.hpp"
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
namespace xo {
|
||||
namespace mm {
|
||||
|
||||
/** @brief configuration for MutationLogState **/
|
||||
class MutationLogConfig {
|
||||
public:
|
||||
MutationLogConfig(std::uint32_t ngen,
|
||||
std::uint32_t survive,
|
||||
std::size_t mlog_z,
|
||||
bool debug_flag);
|
||||
|
||||
/** age threshold for promotion to generation @p g **/
|
||||
uint32_t promotion_threshold(Generation g) const noexcept {
|
||||
|
||||
// TODO: may consider replacing with table-lookup
|
||||
// Require: if two distinct ages promote to some gen g at the same time,
|
||||
// then they also promote to gen g+k at the same time for all k>0.
|
||||
|
||||
return g * n_survive_threshold_;
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
/** number of generations in use.
|
||||
* Same as @ref X1CollectorConfig::n_generation_
|
||||
**/
|
||||
std::uint32_t n_generation_ = 0;
|
||||
|
||||
/** Number of promotion steps.
|
||||
* An object that survives this number of collections
|
||||
* advances to the next generation.
|
||||
**/
|
||||
uint32_t n_survive_threshold_ = 2;
|
||||
|
||||
/** storage for xgen pointer bookkeeping (aka remembered sets).
|
||||
* Use 3x this value per generation
|
||||
**/
|
||||
|
|
|
|||
|
|
@ -130,7 +130,7 @@ namespace xo {
|
|||
* helper function to decide whether to keep a mutation log entry
|
||||
* @return true iff mlog entry appended to @p keep_mlog
|
||||
**/
|
||||
bool _check_keep_mutation_aux(DX1Collector * gc,
|
||||
bool _check_keep_mutation_aux(const GCObjectStore & gco_store,
|
||||
const MutationLogEntry & from_entry,
|
||||
Generation parent_gen_to,
|
||||
void * child_to,
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "GCObjectStoreConfig.hpp"
|
||||
#include "MutationLogConfig.hpp"
|
||||
#include "object_age.hpp"
|
||||
#include "generation.hpp"
|
||||
#include <xo/arena/ArenaConfig.hpp>
|
||||
|
|
@ -36,18 +38,28 @@ namespace xo {
|
|||
**/
|
||||
X1CollectorConfig with_sanitize_flag(bool x);
|
||||
|
||||
/** fetch configuration for gc object store **/
|
||||
GCObjectStoreConfig gco_store_config() const noexcept {
|
||||
return GCObjectStoreConfig(arena_config_,
|
||||
n_generation_,
|
||||
debug_flag_);
|
||||
}
|
||||
|
||||
/** fetch configuration for mutation log store **/
|
||||
MutationLogConfig mlog_config() const noexcept {
|
||||
return MutationLogConfig(n_generation_,
|
||||
n_survive_threshold_,
|
||||
mutation_log_z_,
|
||||
debug_flag_);
|
||||
}
|
||||
|
||||
Generation age2gen(object_age age) const noexcept {
|
||||
return Generation(age % n_survive_threshold_);
|
||||
}
|
||||
|
||||
/** age threshold for promotion to generation @p g **/
|
||||
uint32_t promotion_threshold(Generation g) const noexcept {
|
||||
|
||||
// TODO: may consider replacing with table-lookup
|
||||
// Require: if two distinct ages promote to some gen g at the same time,
|
||||
// then they also promote to gen g+k at the same time for all k>0.
|
||||
|
||||
return g * n_survive_threshold_;
|
||||
return mlog_config().promotion_threshold(g);
|
||||
}
|
||||
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -9,18 +9,21 @@ set(SELF_SRCS
|
|||
IAllocator_DX1Collector.cpp
|
||||
IAllocIterator_DX1CollectorIterator.cpp
|
||||
|
||||
X1CollectorConfig.cpp
|
||||
DX1Collector.cpp
|
||||
facet/ICollector_DX1Collector.cpp
|
||||
|
||||
DX1CollectorIterator.cpp
|
||||
|
||||
X1CollectorConfig.cpp
|
||||
GCObjectStoreConfig.cpp
|
||||
GCObjectStore.cpp
|
||||
|
||||
MutationLogConfig.cpp
|
||||
MutationLogState.cpp
|
||||
MutationLogEntry.cpp
|
||||
|
||||
|
||||
|
||||
)
|
||||
|
||||
xo_add_shared_library4(${SELF_LIB} ${PROJECT_NAME}Targets ${PROJECT_VERSION} 1 ${SELF_SRCS})
|
||||
|
|
|
|||
|
|
@ -67,12 +67,8 @@ namespace xo {
|
|||
|
||||
DX1Collector::DX1Collector(const X1CollectorConfig & cfg)
|
||||
: config_{cfg},
|
||||
mlog_state_{
|
||||
MutationLogConfig{
|
||||
cfg.n_generation_,
|
||||
cfg.mutation_log_z_,
|
||||
cfg.debug_flag_}},
|
||||
gco_store_{cfg.arena_config_, cfg.n_generation_, cfg.debug_flag_}
|
||||
mlog_state_{cfg.mlog_config()},
|
||||
gco_store_{cfg.gco_store_config()}
|
||||
{
|
||||
assert(config_.arena_config_.header_.size_bits_ +
|
||||
config_.arena_config_.header_.age_bits_ +
|
||||
|
|
|
|||
|
|
@ -10,15 +10,12 @@
|
|||
namespace xo {
|
||||
namespace mm {
|
||||
|
||||
GCObjectStore::GCObjectStore(const ArenaConfig & arena_cfg,
|
||||
uint32_t ngen, bool debug_flag)
|
||||
: arena_config_{arena_cfg},
|
||||
n_generation_{ngen},
|
||||
debug_flag_{debug_flag}
|
||||
GCObjectStore::GCObjectStore(const GCObjectStoreConfig & cfg)
|
||||
: config_{cfg}
|
||||
{
|
||||
assert(arena_config_.header_.size_bits_ +
|
||||
arena_config_.header_.age_bits_ +
|
||||
arena_config_.header_.tseq_bits_ <= 64);
|
||||
assert(config_.arena_config_.header_.size_bits_ +
|
||||
config_.arena_config_.header_.age_bits_ +
|
||||
config_.arena_config_.header_.tseq_bits_ <= 64);
|
||||
|
||||
this->_init_space();
|
||||
}
|
||||
|
|
@ -28,21 +25,21 @@ namespace xo {
|
|||
{
|
||||
assert(c_n_role == 2);
|
||||
|
||||
for (uint32_t igen = 0, ngen = n_generation_; igen < ngen; ++igen) {
|
||||
for (uint32_t igen = 0, ngen = config_.n_generation_; igen < ngen; ++igen) {
|
||||
if (igen < c_max_generation) {
|
||||
{
|
||||
char buf[40];
|
||||
snprintf(buf, sizeof(buf), "x1-space-G%u-a", igen);
|
||||
|
||||
this->space_storage_[0][igen]
|
||||
= DArena::map(arena_config_.with_name(std::string(buf)));
|
||||
= DArena::map(config_.arena_config_.with_name(std::string(buf)));
|
||||
}
|
||||
{
|
||||
char buf[40];
|
||||
snprintf(buf, sizeof(buf), "x1-space-G%u-b", igen);
|
||||
|
||||
this->space_storage_[1][igen]
|
||||
= DArena::map(arena_config_.with_name(std::string(buf)));
|
||||
= DArena::map(config_.arena_config_.with_name(std::string(buf)));
|
||||
}
|
||||
|
||||
this->space_[role::to_space()][igen] = &space_storage_[0][igen];
|
||||
|
|
@ -52,12 +49,12 @@ namespace xo {
|
|||
}
|
||||
}
|
||||
|
||||
for (uint32_t igen = n_generation_; igen < c_max_generation; ++igen) {
|
||||
for (uint32_t igen = config_.n_generation_; igen < c_max_generation; ++igen) {
|
||||
this->space_[role::to_space()][igen] = nullptr;
|
||||
this->space_[role::from_space()][igen] = nullptr;
|
||||
}
|
||||
|
||||
if (n_generation_ == 2) {
|
||||
if (config_.n_generation_ == 2) {
|
||||
assert(this->get_space(role::to_space(), Generation{2}) == nullptr);
|
||||
}
|
||||
}
|
||||
|
|
@ -65,7 +62,7 @@ namespace xo {
|
|||
Generation
|
||||
GCObjectStore::generation_of(role r, const void * addr) const noexcept
|
||||
{
|
||||
for (Generation gi{0}; gi < n_generation_; ++gi) {
|
||||
for (Generation gi{0}; gi < config_.n_generation_; ++gi) {
|
||||
const DArena * arena = this->get_space(r, gi);
|
||||
|
||||
if (arena->contains(addr))
|
||||
|
|
@ -78,7 +75,7 @@ namespace xo {
|
|||
auto
|
||||
GCObjectStore::header2size(header_type hdr) const noexcept -> size_type
|
||||
{
|
||||
uint32_t z = arena_config_.header_.size(hdr);
|
||||
uint32_t z = config_.arena_config_.header_.size(hdr);
|
||||
|
||||
return z;
|
||||
}
|
||||
|
|
@ -86,7 +83,7 @@ namespace xo {
|
|||
object_age
|
||||
GCObjectStore::header2age(header_type hdr) const noexcept
|
||||
{
|
||||
uint32_t age = arena_config_.header_.age(hdr);
|
||||
uint32_t age = config_.arena_config_.header_.age(hdr);
|
||||
|
||||
assert(age < c_max_object_age);
|
||||
|
||||
|
|
@ -96,7 +93,7 @@ namespace xo {
|
|||
uint32_t
|
||||
GCObjectStore::header2tseq(header_type hdr) const noexcept
|
||||
{
|
||||
uint32_t tseq = arena_config_.header_.tseq(hdr);
|
||||
uint32_t tseq = config_.arena_config_.header_.tseq(hdr);
|
||||
|
||||
return tseq;
|
||||
}
|
||||
|
|
@ -105,13 +102,13 @@ namespace xo {
|
|||
GCObjectStore::is_forwarding_header(header_type hdr) const noexcept
|
||||
{
|
||||
/** forwarding pointer encoded as sentinel tseq **/
|
||||
return arena_config_.header_.is_forwarding_tseq(hdr);
|
||||
return config_.arena_config_.header_.is_forwarding_tseq(hdr);
|
||||
}
|
||||
|
||||
void
|
||||
GCObjectStore::visit_pools(const MemorySizeVisitor & visitor) const
|
||||
{
|
||||
for (uint32_t j = 0; j < n_generation_; ++j) {
|
||||
for (uint32_t j = 0; j < config_.n_generation_; ++j) {
|
||||
for (uint32_t i = 0; i < c_n_role; ++i) {
|
||||
space_storage_[i][j].visit_pools(visitor);
|
||||
}
|
||||
|
|
@ -121,7 +118,7 @@ namespace xo {
|
|||
void
|
||||
GCObjectStore::swap_roles(Generation upto) noexcept
|
||||
{
|
||||
scope log(XO_DEBUG(debug_flag_), xtag("upto", upto));
|
||||
scope log(XO_DEBUG(config_.debug_flag_), xtag("upto", upto));
|
||||
|
||||
for (Generation g = Generation{0}; g < upto; ++g) {
|
||||
log && log("swap roles", xtag("g", g));
|
||||
|
|
@ -134,7 +131,7 @@ namespace xo {
|
|||
GCObjectStore::cleanup_phase(Generation upto,
|
||||
bool sanitize_flag)
|
||||
{
|
||||
scope log(XO_DEBUG(debug_flag_), xtag("upto", upto));
|
||||
scope log(XO_DEBUG(config_.debug_flag_), xtag("upto", upto));
|
||||
|
||||
// everything live has been copied out of from-space
|
||||
// -> now set to empty
|
||||
|
|
|
|||
22
src/gc/GCObjectStoreConfig.cpp
Normal file
22
src/gc/GCObjectStoreConfig.cpp
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
/** @file GCObjectStore.cpp
|
||||
*
|
||||
* @author Roland Conybeare, Apr 2026
|
||||
**/
|
||||
|
||||
#include "GCObjectStore.hpp"
|
||||
|
||||
namespace xo {
|
||||
namespace mm {
|
||||
|
||||
GCObjectStoreConfig::GCObjectStoreConfig(const ArenaConfig & arena_cfg,
|
||||
std::uint32_t ngen,
|
||||
bool debug_flag)
|
||||
: arena_config_{arena_cfg},
|
||||
n_generation_{ngen},
|
||||
debug_flag_{debug_flag}
|
||||
{}
|
||||
|
||||
} /*namespace mm*/
|
||||
} /*namespace xo*/
|
||||
|
||||
/* end GCObjectStore.cpp */
|
||||
|
|
@ -9,9 +9,11 @@ namespace xo {
|
|||
namespace mm {
|
||||
|
||||
MutationLogConfig::MutationLogConfig(std::uint32_t ngen,
|
||||
std::uint32_t survive,
|
||||
std::size_t mlog_z,
|
||||
bool debug_flag)
|
||||
: n_generation_{ngen},
|
||||
n_survive_threshold_{survive},
|
||||
mutation_log_z_{mlog_z},
|
||||
debug_flag_{debug_flag}
|
||||
{}
|
||||
|
|
|
|||
|
|
@ -332,7 +332,7 @@ namespace xo {
|
|||
|
||||
MutationLogEntry to_entry(parent_to, p_data_to, from_entry.snap());
|
||||
|
||||
this->_check_keep_mutation_aux(gc,
|
||||
this->_check_keep_mutation_aux(gc->gco_store(),
|
||||
to_entry,
|
||||
parent_gen_to,
|
||||
child_to,
|
||||
|
|
@ -408,25 +408,26 @@ namespace xo {
|
|||
|
||||
// child_to generation in {gen, gen+1}
|
||||
|
||||
this->_check_keep_mutation_aux(gc, from_entry, parent_gen, child_to, keep_mlog);
|
||||
this->_check_keep_mutation_aux(gc->gco_store(),
|
||||
from_entry, parent_gen, child_to, keep_mlog);
|
||||
|
||||
return counters;
|
||||
}
|
||||
|
||||
bool
|
||||
MutationLogState::_check_keep_mutation_aux(DX1Collector * gc,
|
||||
MutationLogState::_check_keep_mutation_aux(const GCObjectStore & gco_store,
|
||||
const MutationLogEntry & from_entry,
|
||||
Generation parent_gen_to,
|
||||
void * child_to,
|
||||
MutationLog * keep_mlog)
|
||||
{
|
||||
Generation child_gen_to
|
||||
= gc->generation_of(role::to_space(), child_to);
|
||||
= gco_store.generation_of(role::to_space(), child_to);
|
||||
|
||||
bool need_mlog_entry
|
||||
= ((child_gen_to + 1 < config_.n_generation_)
|
||||
&& (gc->config().promotion_threshold(parent_gen_to)
|
||||
> gc->config().promotion_threshold(child_gen_to)));
|
||||
&& (config_.promotion_threshold(parent_gen_to)
|
||||
> config_.promotion_threshold(child_gen_to)));
|
||||
|
||||
if (need_mlog_entry) {
|
||||
// 1. P->C pointer is still cross-age (xage), and
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue