diff --git a/include/xo/gc/MutationLogConfig.hpp b/include/xo/gc/MutationLogConfig.hpp index e10f228..08b75e1 100644 --- a/include/xo/gc/MutationLogConfig.hpp +++ b/include/xo/gc/MutationLogConfig.hpp @@ -17,55 +17,26 @@ 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 enabled_flag, 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 { - - // 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_; - } -#endif - public: /** number of generations in use. * Same as @ref X1CollectorConfig::n_generation_ **/ 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 **/ std::size_t mutation_log_z_ = 1024; + /** true if mlog feature enabled (i.e. incremental gc enabled). + * false to disable (in which case only full gc supported) + **/ + bool enabled_flag_ = false; + /** true to enable debug logging **/ bool debug_flag_ = false; }; diff --git a/include/xo/gc/MutationLogStore.hpp b/include/xo/gc/MutationLogStore.hpp index 677baeb..6d2604b 100644 --- a/include/xo/gc/MutationLogStore.hpp +++ b/include/xo/gc/MutationLogStore.hpp @@ -40,13 +40,40 @@ namespace xo { void visit_pools(const MemorySizeVisitor & visitor) const; /** verify consistent mlog state, - * on behalf of collector @p gc. + * on behalf of gc-aware object store @p gc. * (using gc to identify location of objects). * Update counters in @p *p_verify_stats. **/ void verify_ok(GCObjectStore * gc, X1VerifyStats * p_verify_stats) noexcept; + /** on behalf of gc-aware object store @p gc, + * change the value of a child pointer at @p p_lhs + * with parent object @p parent. p_lhs and parent must belong + * to the same allocation. + **/ + void assign_member(GCObjectStore * gc, + void * parent, + obj * p_lhs, + obj rhs); + + /** swap {to, from} roles + **/ + void swap_roles(Generation upto) noexcept; + + /** On behalf of collector @p gc: + * + * forward mutation logs, for generations 0 <= g < @p upto, + * from from-space to to-space. + **/ + void forward_mutation_log(DX1Collector * gc, + Generation upto); + + private: + /** aux init function: create mutation log **/ + MutationLog _make_mlog(uint32_t igen, char tag_char, + size_t mlog_z, std::size_t page_z); + /** Append a single mutation to log for generation @p dest_g * Mutation modifies @p parent at address @p addr, * to refer to @p rhs. @@ -64,27 +91,10 @@ namespace xo { * pointer. This means can alway recover that pointer * by consulting the AllocHeader for the pointer target */ - void append_mutation(Generation dest_g, - void * parent, - void ** addr, - obj rhs); - - /** swap {to, from} roles - **/ - void swap_roles(Generation upto) noexcept; - - /** On behalf of collector @p gc: - * - * forward mutation logs, for generations 0 <= g < @p upto, - * from from-space to to-space. - **/ - void forward_mutation_log(DX1Collector * gc, - Generation upto); - - private: - /** aux init function: create mutation log **/ - MutationLog _make_mlog(uint32_t igen, char tag_char, - size_t mlog_z, std::size_t page_z); + void _append_mutation(Generation dest_g, + void * parent, + void ** addr, + obj rhs); /** On behalf of collctor @p gc: * diff --git a/include/xo/gc/X1CollectorConfig.hpp b/include/xo/gc/X1CollectorConfig.hpp index 38f2d5f..5bbc377 100644 --- a/include/xo/gc/X1CollectorConfig.hpp +++ b/include/xo/gc/X1CollectorConfig.hpp @@ -51,8 +51,11 @@ namespace xo { /** fetch configuration for mutation log store **/ MutationLogConfig mlog_config() const noexcept { + bool mlog_enabled_flag = allow_incremental_gc_; + return MutationLogConfig(n_generation_, mutation_log_z_, + mlog_enabled_flag, debug_flag_); } diff --git a/src/gc/DX1Collector.cpp b/src/gc/DX1Collector.cpp index de2ea71..c4e754c 100644 --- a/src/gc/DX1Collector.cpp +++ b/src/gc/DX1Collector.cpp @@ -701,78 +701,19 @@ namespace xo { // ++ stats.n_mutation_; - *p_lhs = rhs; - if (runstate_.is_running()) { + *p_lhs = rhs; + // for removal of all doubt: - // don't log mutations during GC cycle + // don't log mutations during GC cycle. + // That said: should not be happening! + assert(false); + return; - } - - if (!config_.allow_incremental_gc_) { - // only need to log mutations when incremental gc is enabled - return; - } - - // logging policy depends on: - // 1. generation of lhs - // 2. generation of rhs - - Generation src_g = this->generation_of(role::to_space(), p_lhs); - - if (src_g.is_sentinel()) { - // only need mlog entries for gc-owned pointers. - // In this case pointer does not originate in gc-owned space - return; - } - - Generation dest_g = this->generation_of(role::to_space(), rhs.data()); - - if (dest_g.is_sentinel()) { - // similarly, don't need mlog entry to non-gc-owned destination - return; - } - - if (src_g < dest_g) { - // young-to-old pointers don't need to be remembered, - // since a GC cycle that collects an (old) generation is guarnatted - // to also collect all younger generations. - return; - } - - if (src_g == dest_g) { - // for pointers within the same generation, need to log - // if source is older than destination. - - const DArena * arena = this->get_space(role::to_space(), src_g); - - const DArena::header_type * src_hdr = arena->obj2hdr(parent); - const DArena::header_type * dest_hdr = arena->obj2hdr(rhs.data()); - - assert(src_hdr && dest_hdr); - - if (this->header2age(*src_hdr) <= this->header2age(*dest_hdr)) { - // source and destination have the same age; - // therefore are always collected on the same set of GC cycles - // -> no need to remember separately. - return; - } else { - // even though {src,dest} belong to the same generation: - // source will be eligible for promotion before destination. - // At that point pointer would become a cross-generational pointer, - // so need to track it now. - - log && log("xage ptr -> must log"); - } } else { - log && log("xgen ptr -> must log"); + mlog_store_.assign_member(&gco_store_, parent, p_lhs, rhs); + } - - // control here: we have an older->younger pointer, need to log it - - void ** lhs_addr = reinterpret_cast(&(p_lhs->data_)); - - mlog_store_.append_mutation(dest_g, parent, lhs_addr, rhs); } /*assign_member*/ DX1CollectorIterator @@ -814,15 +755,6 @@ namespace xo { arena_end); } -#ifdef MOVED - void - DX1Collector::reverse_roles(Generation g) noexcept { - assert(g < config_.n_generation_); - - std::swap(space_[role::from_space()][g], space_[role::to_space()][g]); - } -#endif - void DX1Collector::clear() noexcept { for (role ri : role::all()) { diff --git a/src/gc/MutationLogConfig.cpp b/src/gc/MutationLogConfig.cpp index ed18a17..dd1357a 100644 --- a/src/gc/MutationLogConfig.cpp +++ b/src/gc/MutationLogConfig.cpp @@ -9,16 +9,12 @@ namespace xo { namespace mm { MutationLogConfig::MutationLogConfig(std::uint32_t ngen, -#ifdef OBSOLETE - std::uint32_t survive, -#endif std::size_t mlog_z, + bool enabled_flag, bool debug_flag) : n_generation_{ngen}, -#ifdef OBSOLETE - n_survive_threshold_{survive}, -#endif mutation_log_z_{mlog_z}, + enabled_flag_{enabled_flag}, debug_flag_{debug_flag} {} diff --git a/src/gc/MutationLogStore.cpp b/src/gc/MutationLogStore.cpp index c22ef71..20d5254 100644 --- a/src/gc/MutationLogStore.cpp +++ b/src/gc/MutationLogStore.cpp @@ -136,10 +136,89 @@ namespace xo { } /*verify_ok*/ void - MutationLogStore::append_mutation(Generation dest_g, - void * parent, - void ** addr, - obj rhs) + MutationLogStore::assign_member(GCObjectStore * gco_store, + void * parent, + obj * p_lhs, + obj rhs) + { + scope log(XO_DEBUG(config_.debug_flag_), + xtag("parent", parent), xtag("lhs", p_lhs), xtag("rhs", rhs.data())); + + // ++ stats.n_mutation_; + + *p_lhs = rhs; + + if (!config_.enabled_flag_) { + // only need to log mutations when incremental gc is enabled + return; + } + + // logging policy depends on: + // 1. generation of lhs + // 2. generation of rhs + + Generation src_g = gco_store->generation_of(role::to_space(), p_lhs); + + if (src_g.is_sentinel()) { + // only need mlog entries for gc-owned pointers. + // In this case pointer does not originate in gc-owned space + return; + } + + Generation dest_g = gco_store->generation_of(role::to_space(), rhs.data()); + + if (dest_g.is_sentinel()) { + // similarly, don't need mlog entry to non-gc-owned destination + return; + } + + if (src_g < dest_g) { + // young-to-old pointers don't need to be remembered, + // since a GC cycle that collects an (old) generation is guarnatted + // to also collect all younger generations. + return; + } + + if (src_g == dest_g) { + // for pointers within the same generation, need to log + // if source is older than destination. + + const DArena * arena = gco_store->get_space(role::to_space(), src_g); + + const DArena::header_type * src_hdr = arena->obj2hdr(parent); + const DArena::header_type * dest_hdr = arena->obj2hdr(rhs.data()); + + assert(src_hdr && dest_hdr); + + if (gco_store->header2age(*src_hdr) <= gco_store->header2age(*dest_hdr)) { + // source and destination have the same age; + // therefore are always collected on the same set of GC cycles + // -> no need to remember separately. + return; + } else { + // even though {src,dest} belong to the same generation: + // source will be eligible for promotion before destination. + // At that point pointer would become a cross-generational pointer, + // so need to track it now. + + log && log("xage ptr -> must log"); + } + } else { + log && log("xgen ptr -> must log"); + } + + // control here: we have an older->younger pointer, need to log it + + void ** lhs_addr = reinterpret_cast(&(p_lhs->data_)); + + this->_append_mutation(dest_g, parent, lhs_addr, rhs); + } + + void + MutationLogStore::_append_mutation(Generation dest_g, + void * parent, + void ** addr, + obj rhs) { // mlog keyed by generation in which pointer _destination_ resides: // collection that moves destination generation around needs to also