diff --git a/include/xo/gc/GCObjectStore.hpp b/include/xo/gc/GCObjectStore.hpp index 0b0d33a..dff223c 100644 --- a/include/xo/gc/GCObjectStore.hpp +++ b/include/xo/gc/GCObjectStore.hpp @@ -26,6 +26,8 @@ namespace xo { public: explicit GCObjectStore(const GCObjectStoreConfig & cfg); + const GCObjectStoreConfig & config() const noexcept { return config_; } + 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]; } DArena * from_space(Generation g) noexcept { return get_space(role::from_space(), g); } @@ -53,6 +55,27 @@ namespace xo { /** Call @p visitor for each memory pool owned by this store **/ void visit_pools(const MemorySizeVisitor & visitor) const; + /** true iff address @p addr allocated from this collector + * in role @p r (according to current GC state) + **/ + bool contains(role r, const void * addr) const noexcept; + + /** true iff address @p addr allocated from this collector and currently live + * in role @p r (according to current GC state) + * + * (i.e. in [lo,free) for an arena) + **/ + bool contains_allocated(role r, const void * addr) const noexcept; + + /** true iff {@p alloc_hdr, @p object_data} should move for + * a collection of all generations strictly younger than @p upto. + * + * Require: runstate_.is_running() + **/ + bool check_move_policy(Generation upto, + header_type alloc_hdr, + void * gco_data) const noexcept; + /** For each generation g in [0 ,.., upto) * swap arenas assigned to {to-space, from-space}. * Invoked once at the beginning of each gc cycle. diff --git a/include/xo/gc/GCObjectStoreConfig.hpp b/include/xo/gc/GCObjectStoreConfig.hpp index 40e4483..a5512d1 100644 --- a/include/xo/gc/GCObjectStoreConfig.hpp +++ b/include/xo/gc/GCObjectStoreConfig.hpp @@ -5,6 +5,8 @@ #pragma once +#include "generation.hpp" +#include "object_age.hpp" #include namespace xo { @@ -15,8 +17,30 @@ namespace xo { public: GCObjectStoreConfig(const ArenaConfig & arena_cfg, std::uint32_t ngen, + std::uint32_t nsurvive, bool debug_flag); + /** generation that would contain an object that has survived + * @p age collections. Equals the number of times object + * has been promoted. + * + * Must be consistent + **/ + 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_; + } + + public: /** Configuration for collector spaces. * Will have (2 x G) of these, @@ -27,8 +51,16 @@ namespace xo { * - 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; + + /** Number of promotion steps. + * An object that survives this number of collections + * advances to the next generation. + **/ + std::uint32_t n_survive_threshold_ = 2; + /** true to enable debug logging **/ bool debug_flag_ = false; }; diff --git a/include/xo/gc/MutationLogConfig.hpp b/include/xo/gc/MutationLogConfig.hpp index 89d7041..b499045 100644 --- a/include/xo/gc/MutationLogConfig.hpp +++ b/include/xo/gc/MutationLogConfig.hpp @@ -5,6 +5,7 @@ #pragma once +#include "object_age.hpp" #include "generation.hpp" #include #include @@ -16,10 +17,25 @@ namespace xo { class MutationLogConfig { public: MutationLogConfig(std::uint32_t ngen, +#ifdef OBSOLETE // in GCObjectStore std::uint32_t survive, +#endif std::size_t mlog_z, bool debug_flag); +#ifdef OBSOLETE + /** generation that would contain an object that has survived + * @p age collections. Equals the number of times object + * has been promoted. + * + * Must be consistent + **/ + Generation age2gen(object_age age) const noexcept { + return Generation(age % n_survive_threshold_); + } +#endif + +#ifdef OBSOLETE /** age threshold for promotion to generation @p g **/ uint32_t promotion_threshold(Generation g) const noexcept { @@ -29,7 +45,7 @@ namespace xo { return g * n_survive_threshold_; } - +#endif public: /** number of generations in use. @@ -37,11 +53,13 @@ namespace xo { **/ std::uint32_t n_generation_ = 0; +#ifdef OBSOLETE /** Number of promotion steps. * An object that survives this number of collections * advances to the next generation. **/ uint32_t n_survive_threshold_ = 2; +#endif /** storage for xgen pointer bookkeeping (aka remembered sets). * Use 3x this value per generation diff --git a/include/xo/gc/X1CollectorConfig.hpp b/include/xo/gc/X1CollectorConfig.hpp index 03a4b11..3e46b67 100644 --- a/include/xo/gc/X1CollectorConfig.hpp +++ b/include/xo/gc/X1CollectorConfig.hpp @@ -42,24 +42,27 @@ namespace xo { GCObjectStoreConfig gco_store_config() const noexcept { return GCObjectStoreConfig(arena_config_, n_generation_, + n_survive_threshold_, debug_flag_); } /** fetch configuration for mutation log store **/ MutationLogConfig mlog_config() const noexcept { return MutationLogConfig(n_generation_, +#ifdef OBSOLETE n_survive_threshold_, +#endif mutation_log_z_, debug_flag_); } Generation age2gen(object_age age) const noexcept { - return Generation(age % n_survive_threshold_); + return this->gco_store_config().age2gen(age); } /** age threshold for promotion to generation @p g **/ uint32_t promotion_threshold(Generation g) const noexcept { - return mlog_config().promotion_threshold(g); + return this->gco_store_config().promotion_threshold(g); } public: diff --git a/src/gc/DX1Collector.cpp b/src/gc/DX1Collector.cpp index 12070bb..2df998f 100644 --- a/src/gc/DX1Collector.cpp +++ b/src/gc/DX1Collector.cpp @@ -124,18 +124,13 @@ namespace xo { bool DX1Collector::contains(role r, const void * addr) const noexcept { - return !(this->generation_of(r, addr).is_sentinel()); + return gco_store_.contains(r, addr); } bool DX1Collector::contains_allocated(role r, const void * addr) const noexcept { - Generation g = this->generation_of(r, addr); - - if (g.is_sentinel()) - return false; - - return this->get_space(r, g)->contains_allocated(addr); + return gco_store_.contains_allocated(r, addr); } Generation @@ -212,16 +207,6 @@ namespace xo { DX1Collector::mutation_log_entries() const noexcept { return mlog_state_.mutation_log_entries(); - -#ifdef MOVED - size_type z = 0; - - for (Generation gj{0}; gj + 1 < config_.n_generation_; ++gj) { - z += mlog_[role::to_space()][gj]->size(); - } - - return z; -#endif } namespace { @@ -1397,19 +1382,11 @@ namespace xo { DX1Collector::check_move_policy(header_type alloc_hdr, void * object_data) const noexcept { - (void)object_data; - - // when gc is moving objects, to- and from- spaces have been - // reversed: forwarding pointers are located in from-space and - // refer to to-space. - - object_age age = this->header2age(alloc_hdr); - - Generation g = config_.age2gen(age); - assert(runstate_.is_running()); - return (g < runstate_.gc_upto()); + return gco_store_.check_move_policy(runstate_.gc_upto(), + alloc_hdr, + object_data); } auto diff --git a/src/gc/GCObjectStore.cpp b/src/gc/GCObjectStore.cpp index 576534f..3ba98e8 100644 --- a/src/gc/GCObjectStore.cpp +++ b/src/gc/GCObjectStore.cpp @@ -133,10 +133,48 @@ namespace xo { } } + bool + GCObjectStore::contains(role r, const void * addr) const noexcept + { + return !(this->generation_of(r, addr).is_sentinel()); + } + + bool + GCObjectStore::contains_allocated(role r, const void * addr) const noexcept + { + Generation g = this->generation_of(r, addr); + + if (g.is_sentinel()) + return false; + + return this->get_space(r, g)->contains_allocated(addr); + } + + bool + GCObjectStore::check_move_policy(Generation upto, + header_type alloc_hdr, + void * object_data) const noexcept + { + (void)object_data; + + // when gc is moving objects, to- and from- spaces have been + // reversed: forwarding pointers are located in from-space and + // refer to to-space. + + object_age age = this->header2age(alloc_hdr); + + Generation g = config_.age2gen(age); + + //assert(runstate_.is_running()); + + return (g < upto); + } + void GCObjectStore::swap_roles(Generation upto) noexcept { - scope log(XO_DEBUG(config_.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)); diff --git a/src/gc/GCObjectStoreConfig.cpp b/src/gc/GCObjectStoreConfig.cpp index 1d765a8..560d7c3 100644 --- a/src/gc/GCObjectStoreConfig.cpp +++ b/src/gc/GCObjectStoreConfig.cpp @@ -10,9 +10,11 @@ namespace xo { GCObjectStoreConfig::GCObjectStoreConfig(const ArenaConfig & arena_cfg, std::uint32_t ngen, + std::uint32_t nsurvive, bool debug_flag) : arena_config_{arena_cfg}, n_generation_{ngen}, + n_survive_threshold_{nsurvive}, debug_flag_{debug_flag} {} diff --git a/src/gc/MutationLogConfig.cpp b/src/gc/MutationLogConfig.cpp index ff2af63..ed18a17 100644 --- a/src/gc/MutationLogConfig.cpp +++ b/src/gc/MutationLogConfig.cpp @@ -9,11 +9,15 @@ namespace xo { namespace mm { MutationLogConfig::MutationLogConfig(std::uint32_t ngen, +#ifdef OBSOLETE std::uint32_t survive, +#endif std::size_t mlog_z, bool debug_flag) : n_generation_{ngen}, +#ifdef OBSOLETE n_survive_threshold_{survive}, +#endif mutation_log_z_{mlog_z}, debug_flag_{debug_flag} {} diff --git a/src/gc/MutationLogState.cpp b/src/gc/MutationLogState.cpp index b6198f2..33c1ca7 100644 --- a/src/gc/MutationLogState.cpp +++ b/src/gc/MutationLogState.cpp @@ -426,8 +426,8 @@ namespace xo { bool need_mlog_entry = ((child_gen_to + 1 < config_.n_generation_) - && (config_.promotion_threshold(parent_gen_to) - > config_.promotion_threshold(child_gen_to))); + && (gco_store.config().promotion_threshold(parent_gen_to) + > gco_store.config().promotion_threshold(child_gen_to))); if (need_mlog_entry) { // 1. P->C pointer is still cross-age (xage), and