xo-gc: improve public/private between MutationLogStore and X1
This commit is contained in:
parent
f71d40e4a0
commit
5d3c088ba7
6 changed files with 133 additions and 142 deletions
|
|
@ -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;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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<AGCObject> * p_lhs,
|
||||
obj<AGCObject> 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<AGCObject> 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<AGCObject> rhs);
|
||||
|
||||
/** On behalf of collctor @p gc:
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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_);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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<void **>(&(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()) {
|
||||
|
|
|
|||
|
|
@ -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}
|
||||
{}
|
||||
|
||||
|
|
|
|||
|
|
@ -136,10 +136,89 @@ namespace xo {
|
|||
} /*verify_ok*/
|
||||
|
||||
void
|
||||
MutationLogStore::append_mutation(Generation dest_g,
|
||||
void * parent,
|
||||
void ** addr,
|
||||
obj<AGCObject> rhs)
|
||||
MutationLogStore::assign_member(GCObjectStore * gco_store,
|
||||
void * parent,
|
||||
obj<AGCObject> * p_lhs,
|
||||
obj<AGCObject> 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<void **>(&(p_lhs->data_));
|
||||
|
||||
this->_append_mutation(dest_g, parent, lhs_addr, rhs);
|
||||
}
|
||||
|
||||
void
|
||||
MutationLogStore::_append_mutation(Generation dest_g,
|
||||
void * parent,
|
||||
void ** addr,
|
||||
obj<AGCObject> rhs)
|
||||
{
|
||||
// mlog keyed by generation in which pointer _destination_ resides:
|
||||
// collection that moves destination generation around needs to also
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue