diff --git a/include/xo/gc/DX1Collector.hpp b/include/xo/gc/DX1Collector.hpp index 7992f47..6fd48b9 100644 --- a/include/xo/gc/DX1Collector.hpp +++ b/include/xo/gc/DX1Collector.hpp @@ -412,7 +412,7 @@ namespace xo { /** aux init function: initialize @ref roots_ arena **/ void _init_gc_roots(const X1CollectorConfig & cfg, std::size_t page_z); /** aux init function: initialize @ref mlog_storage_[][] arenas **/ - void _init_mlogs(const X1CollectorConfig & cfg, std::size_t page_z); + void _init_mlogs(std::size_t page_z); /** aux init function: initialize @ref space_storage_[][] arenas **/ void _init_space(const X1CollectorConfig & cfg); diff --git a/include/xo/gc/MutationLogConfig.hpp b/include/xo/gc/MutationLogConfig.hpp new file mode 100644 index 0000000..c8cd37b --- /dev/null +++ b/include/xo/gc/MutationLogConfig.hpp @@ -0,0 +1,38 @@ +/** @file MutationLogConfig.hpp + * + * @author Roland Conybeare, Apr 2026 + **/ + +#pragma once + +#include +#include + +namespace xo { + namespace mm { + + class MutationLogConfig { + public: + MutationLogConfig(std::uint32_t ngen, + std::size_t mlog_z, + bool debug_flag); + + public: + /** number of generations in use. + * Same as @ref X1CollectorConfig::n_generation_ + **/ + std::uint32_t n_generation_ = 0; + + /** storage for xgen pointer bookkeeping (aka remembered sets). + * Use 3x this value per generation + **/ + std::size_t mutation_log_z_ = 1024; + + /** true to enable debug logging **/ + bool debug_flag_ = false; + }; + + } /*namespace mm*/ +} /*namespace xo*/ + +/* end MutationLogConfig.hpp */ diff --git a/include/xo/gc/MutationLogState.hpp b/include/xo/gc/MutationLogState.hpp index 57c9314..7ca0d18 100644 --- a/include/xo/gc/MutationLogState.hpp +++ b/include/xo/gc/MutationLogState.hpp @@ -5,7 +5,9 @@ #pragma once +#include "MutationLogConfig.hpp" #include "X1CollectorConfig.hpp" +#include "GCObjectStore.hpp" #include "MutationLogStatistics.hpp" #include "MutationLogEntry.hpp" #include @@ -24,12 +26,12 @@ namespace xo { using size_type = DArena::size_type; public: - MutationLogState(uint32_t ngen, bool debug_flag); + explicit MutationLogState(const MutationLogConfig & config); - /** Initialize mlog state for configuration @p cfg + /** Initialize mlog state * with o/s page size @p page_z **/ - void init_mlogs(const X1CollectorConfig & cfg, std::size_t page_z); + void init_mlogs(std::size_t page_z); /** total number of active mlog entries (across all generations) **/ @@ -42,7 +44,7 @@ namespace xo { * (using gc to identify location of objects). * Update counters in @p *p_verify_stats. **/ - void verify_ok(DX1Collector * gc, + void verify_ok(GCObjectStore * gc, VerifyStats * p_verify_stats) noexcept; /** Append a single mutation to log for generation @p dest_g @@ -67,7 +69,8 @@ namespace xo { void ** addr, obj rhs); - /** swap {to, from} roles **/ + /** swap {to, from} roles + **/ void swap_roles(Generation upto) noexcept; /** On behalf of collector @p gc: @@ -135,10 +138,8 @@ namespace xo { public: - /** 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 mlog store **/ + MutationLogConfig config_; /** Cross-generational mutations tracked in MutationLogs. * We need three logs per generation: diff --git a/src/gc/CMakeLists.txt b/src/gc/CMakeLists.txt index 3f61335..ec49a41 100644 --- a/src/gc/CMakeLists.txt +++ b/src/gc/CMakeLists.txt @@ -16,6 +16,8 @@ set(SELF_SRCS X1CollectorConfig.cpp GCObjectStore.cpp + + MutationLogConfig.cpp MutationLogState.cpp MutationLogEntry.cpp diff --git a/src/gc/DX1Collector.cpp b/src/gc/DX1Collector.cpp index de9af1e..5e653eb 100644 --- a/src/gc/DX1Collector.cpp +++ b/src/gc/DX1Collector.cpp @@ -67,7 +67,11 @@ namespace xo { DX1Collector::DX1Collector(const X1CollectorConfig & cfg) : config_{cfg}, - mlog_state_{cfg.n_generation_, cfg.debug_flag_}, + mlog_state_{ + MutationLogConfig{ + cfg.n_generation_, + cfg.mutation_log_z_, + cfg.debug_flag_}}, gco_store_{cfg.arena_config_, cfg.n_generation_, cfg.debug_flag_} { assert(config_.arena_config_.header_.size_bits_ + @@ -78,10 +82,7 @@ namespace xo { this->_init_object_types(cfg, page_z); this->_init_gc_roots(cfg, page_z); - this->_init_mlogs(cfg, page_z); -#ifdef MOVED - this->_init_space(cfg); -#endif + this->_init_mlogs(page_z); } void @@ -109,9 +110,9 @@ namespace xo { } void - DX1Collector::_init_mlogs(const X1CollectorConfig & cfg, std::size_t page_z) + DX1Collector::_init_mlogs(std::size_t page_z) { - this->mlog_state_.init_mlogs(cfg, page_z); + this->mlog_state_.init_mlogs(page_z); } void @@ -145,7 +146,7 @@ namespace xo { DX1Collector::generation_of(role r, const void * addr) const noexcept { for (Generation gi{0}; gi < config_.n_generation_; ++gi) { - const DArena * arena = get_space(r, gi); + const DArena * arena = this->get_space(r, gi); if (arena->contains(addr)) return gi; @@ -693,7 +694,7 @@ namespace xo { } // 4. scan mutation logs - mlog_state_.verify_ok(this, + mlog_state_.verify_ok(&gco_store_, &(this->verify_stats_)); } diff --git a/src/gc/GCObjectStore.cpp b/src/gc/GCObjectStore.cpp index 7819f21..1537d6b 100644 --- a/src/gc/GCObjectStore.cpp +++ b/src/gc/GCObjectStore.cpp @@ -75,7 +75,7 @@ namespace xo { void GCObjectStore::swap_roles(Generation upto) noexcept { - scope log(XO_DEBUG(true), xtag("upto", upto)); + scope log(XO_DEBUG(debug_flag_), xtag("upto", upto)); for (Generation g = Generation{0}; g < upto; ++g) { log && log("swap roles", xtag("g", g)); @@ -88,7 +88,7 @@ namespace xo { GCObjectStore::cleanup_phase(Generation upto, bool sanitize_flag) { - scope log(XO_DEBUG(true), xtag("upto", upto)); + scope log(XO_DEBUG(debug_flag_), xtag("upto", upto)); // everything live has been copied out of from-space // -> now set to empty diff --git a/src/gc/MutationLogConfig.cpp b/src/gc/MutationLogConfig.cpp new file mode 100644 index 0000000..5e2275d --- /dev/null +++ b/src/gc/MutationLogConfig.cpp @@ -0,0 +1,22 @@ +/** @file MutationLogConfig.cpp + * + * @author Roland Conybeare, Apr 2026 + **/ + +#include "MutationLogConfig.hpp" + +namespace xo { + namespace mm { + + MutationLogConfig::MutationLogConfig(std::uint32_t ngen, + std::size_t mlog_z, + bool debug_flag) + : n_generation_{ngen}, + mutation_log_z_{mlog_z}, + debug_flag_{debug_flag} + {} + + } +} + +/* end MutationLogConfig.cpp */ diff --git a/src/gc/MutationLogState.cpp b/src/gc/MutationLogState.cpp index 18c22d3..ba2d51f 100644 --- a/src/gc/MutationLogState.cpp +++ b/src/gc/MutationLogState.cpp @@ -9,36 +9,43 @@ namespace xo { namespace mm { - MutationLogState::MutationLogState(uint32_t ngen, bool debug_flag) - : n_generation_{ngen}, debug_flag_{debug_flag} + MutationLogState::MutationLogState(const MutationLogConfig & config) + : config_{config} {} void - MutationLogState::init_mlogs(const X1CollectorConfig & cfg, - std::size_t page_z) + MutationLogState::init_mlogs(std::size_t page_z) { - for (uint32_t igen = 0, ngen = cfg.n_generation_; igen + 1 < ngen; ++igen) { + assert(c_n_role + 1 == 3); + + for (uint32_t igen = 0, ngen = config_.n_generation_; igen + 1 < ngen; ++igen) { // special case: no use for mutation log for youngest generation, // so don't trouble to allocate one if (igen + 1 < c_max_generation) { - this->mlog_storage_[0][igen] = _make_mlog(igen, 'a', cfg.mutation_log_z_, page_z); - this->mlog_storage_[1][igen] = _make_mlog(igen, 'b', cfg.mutation_log_z_, page_z); - this->mlog_storage_[2][igen] = _make_mlog(igen, 'c', cfg.mutation_log_z_, page_z); + std::array label_v{'a', 'b', 'c'}; - this->mlog_[0][igen] = &mlog_storage_[0][igen]; - this->mlog_[1][igen] = &mlog_storage_[1][igen]; - this->mlog_[2][igen] = &mlog_storage_[2][igen]; + for (std::uint32_t mlog_role = 0; mlog_role < c_n_role + 1; ++mlog_role) { + this->mlog_storage_[mlog_role][igen] + = _make_mlog(igen, + label_v[mlog_role], + config_.mutation_log_z_, + page_z); + + this->mlog_[mlog_role][igen] + = &(mlog_storage_[mlog_role][igen]); + } } else { assert(false); } } - if (cfg.n_generation_ > 0) { - for (uint32_t igen = cfg.n_generation_ - 1; igen + 1 < c_max_generation; ++igen) { - this->mlog_[0][igen] = nullptr; - this->mlog_[1][igen] = nullptr; - this->mlog_[2][igen] = nullptr; + if (config_.n_generation_ > 0) { + for (std::uint32_t igen = config_.n_generation_ - 1; + igen + 1 < c_max_generation; ++igen) { + + for (std::uint32_t mlog_role = 0; mlog_role < c_n_role + 1; ++mlog_role) + this->mlog_[mlog_role][igen] = nullptr; } } else { assert(false); @@ -63,7 +70,7 @@ namespace xo { { size_type z = 0; - for (Generation gj{0}; gj + 1 < n_generation_; ++gj) { + for (Generation gj{0}; gj + 1 < config_.n_generation_; ++gj) { z += mlog_[role::to_space()][gj]->size(); } @@ -73,7 +80,7 @@ namespace xo { void MutationLogState::visit_pools(const MemorySizeVisitor & visitor) const { - for (uint32_t j = 0; j + 1 < n_generation_; ++j) { + for (uint32_t j = 0; j + 1 < config_.n_generation_; ++j) { for (uint32_t i = 0; i < c_n_role + 1; ++i) { mlog_storage_[i][j].visit_pools(visitor); } @@ -81,13 +88,13 @@ namespace xo { } void - MutationLogState::verify_ok(DX1Collector * gc, + MutationLogState::verify_ok(GCObjectStore * gco_store, VerifyStats * p_verify_stats) noexcept { // 4. scan mutation logs - for (Generation g(0); g + 1 < n_generation_; ++g) { - const DArena * space = gc->get_space(role::to_space(), g); - const DArena * from = gc->get_space(role::from_space(), g); + for (Generation g(0); g + 1 < config_.n_generation_; ++g) { + const DArena * space = gco_store->get_space(role::to_space(), g); + const DArena * from = gco_store->get_space(role::from_space(), g); // mutation log for generation g records *incoming* pointers // from more senior generations; includes objects from *this* @@ -168,7 +175,9 @@ namespace xo { // on 1st iteration, for all generations: // - to_mlog, triage_mlog are empty - for (Generation child_gen{0}; child_gen + 2 < n_generation_; ++child_gen) { + for (Generation child_gen{0}; + child_gen + 2 < config_.n_generation_; + ++child_gen) { MutationLog * from_mlog = this->mlog_[role::from_space()][child_gen]; @@ -196,7 +205,7 @@ namespace xo { } while (work > 0); // here: reached fixpoints, any remaining triaged mlogs can be discarded - for (Generation child_gen{0}; child_gen + 2 < n_generation_; ++child_gen) { + for (Generation child_gen{0}; child_gen + 2 < config_.n_generation_; ++child_gen) { MutationLog * triage_mlog = this->mlog_[c_n_role][child_gen]; triage_mlog->clear(); @@ -211,7 +220,7 @@ namespace xo { MutationLog * keep_mlog, MutationLog * triage_mlog) { - scope log(XO_DEBUG(debug_flag_), + scope log(XO_DEBUG(config_.debug_flag_), xtag("child_gen", child_gen), xtag("mlog.size", from_mlog->size())); @@ -415,7 +424,7 @@ namespace xo { = gc->generation_of(role::to_space(), child_to); bool need_mlog_entry - = ((child_gen_to + 1 < n_generation_) + = ((child_gen_to + 1 < config_.n_generation_) && (gc->config().promotion_threshold(parent_gen_to) > gc->config().promotion_threshold(child_gen_to)));