xo-gc: refactor for MutationLogStore bugs [TESTFAIL]
This commit is contained in:
parent
daf7d027be
commit
f79c8a9c73
5 changed files with 154 additions and 19 deletions
|
|
@ -9,6 +9,7 @@
|
||||||
|
|
||||||
namespace xo {
|
namespace xo {
|
||||||
namespace mm {
|
namespace mm {
|
||||||
|
class GCObjectStore; // see xo-gc/ GCObjectStore.hpp
|
||||||
|
|
||||||
/** @brief Track a cross-generational pointer
|
/** @brief Track a cross-generational pointer
|
||||||
*
|
*
|
||||||
|
|
@ -40,6 +41,15 @@ namespace xo {
|
||||||
/** true iff child pointer has been altered since this mlog entry created **/
|
/** true iff child pointer has been altered since this mlog entry created **/
|
||||||
bool is_superseded() const noexcept { return *p_data_ != snap_.data(); }
|
bool is_superseded() const noexcept { return *p_data_ != snap_.data(); }
|
||||||
|
|
||||||
|
/** Refresh snapshot when *p_data_ does not match snap_.data_
|
||||||
|
* Get updated facet information from destination alloc header.
|
||||||
|
* It's possible that *p_data_ no longer points to gc-owned space
|
||||||
|
*
|
||||||
|
* @return true if snapshot updated. false if this entry should be discarded
|
||||||
|
**/
|
||||||
|
bool refresh_snapshot(Generation parent_gen,
|
||||||
|
GCObjectStore * gcos) noexcept;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/** address of object containing logged mutation **/
|
/** address of object containing logged mutation **/
|
||||||
void * parent_ = nullptr;
|
void * parent_ = nullptr;
|
||||||
|
|
|
||||||
|
|
@ -139,18 +139,19 @@ namespace xo {
|
||||||
MutationLogStatistics _preserve_child_of_live_parent(obj<AGCObjectVisitor> gc,
|
MutationLogStatistics _preserve_child_of_live_parent(obj<AGCObjectVisitor> gc,
|
||||||
Generation upto,
|
Generation upto,
|
||||||
Generation parent_gen,
|
Generation parent_gen,
|
||||||
const MutationLogEntry & from_entry,
|
MutationLogEntry & from_entry,
|
||||||
MutationLog * keep_mlog);
|
MutationLog * keep_mlog);
|
||||||
|
|
||||||
|
#ifdef OBSOLETE
|
||||||
/** On behalf of collector @p gc:
|
/** On behalf of collector @p gc:
|
||||||
*
|
*
|
||||||
* helper function to decide whether to keep a mutation log entry
|
* 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(const MutationLogEntry & from_entry,
|
void _check_keep_mutation_aux(MutationLogEntry & from_entry,
|
||||||
Generation parent_gen_to,
|
Generation parent_gen_to,
|
||||||
void * child_to,
|
void * child_to,
|
||||||
MutationLog * keep_mlog);
|
MutationLog * keep_mlog);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,11 @@
|
||||||
**/
|
**/
|
||||||
|
|
||||||
#include "MutationLogEntry.hpp"
|
#include "MutationLogEntry.hpp"
|
||||||
|
#include <xo/gc/GCObjectStore.hpp>
|
||||||
|
|
||||||
namespace xo {
|
namespace xo {
|
||||||
|
using xo::reflect::typeseq;
|
||||||
|
|
||||||
namespace mm {
|
namespace mm {
|
||||||
|
|
||||||
MutationLogEntry::MutationLogEntry(void * parent,
|
MutationLogEntry::MutationLogEntry(void * parent,
|
||||||
|
|
@ -16,6 +19,71 @@ namespace xo {
|
||||||
snap_{snap}
|
snap_{snap}
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
bool
|
||||||
|
MutationLogEntry::refresh_snapshot(Generation parent_gen,
|
||||||
|
GCObjectStore * gcos) noexcept
|
||||||
|
{
|
||||||
|
void * child_data = *p_data_;
|
||||||
|
// note: never the same child_info as computed at the top of
|
||||||
|
// MutationLogEntry._preserve_child_of_live_parent()
|
||||||
|
// Child pointer was either forwarding pointer or moved.
|
||||||
|
// In either case must pickup info for new location.
|
||||||
|
//
|
||||||
|
AllocInfo child_info = gcos->alloc_info((std::byte*)child_data);
|
||||||
|
|
||||||
|
if (child_info.is_forwarding_tseq()) {
|
||||||
|
// code salvaged from MutationLogStore._check_keep_mutation_aux()
|
||||||
|
// as reminder. But if caller is gc will have to know this anyway,
|
||||||
|
// so it can move child
|
||||||
|
|
||||||
|
// if (info.is_forwarding_tseq()) {
|
||||||
|
// child_data = *(void **)child_data;
|
||||||
|
// info = gcos->alloc_info((std::byte *)child_data);
|
||||||
|
//}
|
||||||
|
|
||||||
|
assert(false); // for now assuming caller forward child
|
||||||
|
}
|
||||||
|
|
||||||
|
Generation child_gen_to
|
||||||
|
= gcos->generation_of(Role::to_space(), child_data);
|
||||||
|
|
||||||
|
if (child_gen_to.is_sentinel()) {
|
||||||
|
// child no longer points to gc-owned space.
|
||||||
|
// 1. may not have an alloc header (could be a static global for example),
|
||||||
|
// so AllocInfo not available
|
||||||
|
// 2. doesn't need a mutation log entry since this gc can't move destination
|
||||||
|
|
||||||
|
snap_.data_ = nullptr; // hygiene
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const GCObjectStoreConfig & config = gcos->config();
|
||||||
|
|
||||||
|
bool need_mlog_entry
|
||||||
|
= ((child_gen_to + 1 < config.n_generation_)
|
||||||
|
&& (config.promotion_threshold(parent_gen)
|
||||||
|
> config.promotion_threshold(child_gen_to)));
|
||||||
|
|
||||||
|
if (need_mlog_entry) {
|
||||||
|
AGCObject * iface = gcos->lookup_type(typeseq(child_info.tseq()));
|
||||||
|
|
||||||
|
if (iface) {
|
||||||
|
this->snap_ = obj<AGCObject>(iface, child_data);
|
||||||
|
|
||||||
|
// snapshot updated, keep mlog entry
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
assert(false);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// retire this entry.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} /*namespace mm*/
|
} /*namespace mm*/
|
||||||
} /*namespace xo*/
|
} /*namespace xo*/
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -412,7 +412,8 @@ namespace xo {
|
||||||
assert(!parent_gen_to.is_sentinel());
|
assert(!parent_gen_to.is_sentinel());
|
||||||
|
|
||||||
// Since parent already forwarded, we don't have to preserve child
|
// Since parent already forwarded, we don't have to preserve child
|
||||||
// or update parent object.
|
// or update parent object. GC already guaranteed to have visited
|
||||||
|
// parent's child pointers
|
||||||
//
|
//
|
||||||
// Do need to replace mlog entry to reflect new parent location.
|
// Do need to replace mlog entry to reflect new parent location.
|
||||||
|
|
||||||
|
|
@ -421,14 +422,19 @@ namespace xo {
|
||||||
- (std::byte *)from_entry.parent());
|
- (std::byte *)from_entry.parent());
|
||||||
|
|
||||||
void ** p_data_to = (void **)((std::byte *)(parent_to) + offset);
|
void ** p_data_to = (void **)((std::byte *)(parent_to) + offset);
|
||||||
void * child_to = *p_data_to;
|
//void * child_to = *p_data_to;
|
||||||
|
|
||||||
MutationLogEntry to_entry(parent_to, p_data_to, from_entry.snap());
|
MutationLogEntry to_entry(parent_to, p_data_to, from_entry.snap());
|
||||||
|
|
||||||
|
if (to_entry.refresh_snapshot(parent_gen_to, gco_store_))
|
||||||
|
keep_mlog->push_back(to_entry);
|
||||||
|
|
||||||
|
#ifdef OBSOLETE
|
||||||
this->_check_keep_mutation_aux(to_entry,
|
this->_check_keep_mutation_aux(to_entry,
|
||||||
parent_gen_to,
|
parent_gen_to,
|
||||||
child_to,
|
child_to,
|
||||||
keep_mlog);
|
keep_mlog);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -459,7 +465,7 @@ namespace xo {
|
||||||
MutationLogStore::_preserve_child_of_live_parent(obj<AGCObjectVisitor> gc,
|
MutationLogStore::_preserve_child_of_live_parent(obj<AGCObjectVisitor> gc,
|
||||||
Generation upto,
|
Generation upto,
|
||||||
Generation parent_gen,
|
Generation parent_gen,
|
||||||
const MutationLogEntry & from_entry,
|
MutationLogEntry & from_entry,
|
||||||
MutationLog * keep_mlog)
|
MutationLog * keep_mlog)
|
||||||
{
|
{
|
||||||
void * child_fr = *from_entry.p_data();
|
void * child_fr = *from_entry.p_data();
|
||||||
|
|
@ -487,29 +493,31 @@ namespace xo {
|
||||||
// TODO: make this a method on AllocInfo
|
// TODO: make this a method on AllocInfo
|
||||||
child_to = *(void **)child_fr;
|
child_to = *(void **)child_fr;
|
||||||
|
|
||||||
// assigning through address of P->C pointer
|
|
||||||
// also makes mlog entry current
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// [MLOG2]
|
// [MLOG2]
|
||||||
|
|
||||||
++counters.n_rescue_;
|
++counters.n_rescue_;
|
||||||
|
|
||||||
child_to = gco_store_->deep_move_interior(gc, child_fr, upto);
|
child_to = gco_store_->deep_move_interior(gc, child_fr, upto);
|
||||||
|
}
|
||||||
|
|
||||||
// update child pointer in parent object
|
// update child pointer in parent object.
|
||||||
*from_entry.p_data() = child_to;
|
// either forwarded or moved
|
||||||
|
*from_entry.p_data() = child_to;
|
||||||
|
|
||||||
|
// TODO: pass statistics object
|
||||||
|
if (from_entry.refresh_snapshot(parent_gen, gco_store_)) {
|
||||||
|
keep_mlog->push_back(from_entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
// child_to generation in {gen, gen+1}
|
// child_to generation in {gen, gen+1}
|
||||||
|
|
||||||
this->_check_keep_mutation_aux(from_entry, parent_gen, child_to, keep_mlog);
|
|
||||||
|
|
||||||
return counters;
|
return counters;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
#ifdef OBSOLETE
|
||||||
MutationLogStore::_check_keep_mutation_aux(const MutationLogEntry & from_entry,
|
void
|
||||||
|
MutationLogStore::_check_keep_mutation_aux(MutationLogEntry & from_entry,
|
||||||
Generation parent_gen_to,
|
Generation parent_gen_to,
|
||||||
void * child_to,
|
void * child_to,
|
||||||
MutationLog * keep_mlog)
|
MutationLog * keep_mlog)
|
||||||
|
|
@ -539,6 +547,7 @@ namespace xo {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
} /*namespace mm*/
|
} /*namespace mm*/
|
||||||
|
|
|
||||||
|
|
@ -212,6 +212,51 @@ namespace ut {
|
||||||
|
|
||||||
// ----------------------------------------------------------------
|
// ----------------------------------------------------------------
|
||||||
|
|
||||||
|
static Step step_4[] = {
|
||||||
|
// ----- phase 0 -----
|
||||||
|
{Cmd::make_bool, 0, 0}, // [0]: #f
|
||||||
|
{Cmd::make_bool, 1, 0}, // [1]: #t
|
||||||
|
{Cmd::make_nil, 0, 0}, // [2]: #nil
|
||||||
|
{Cmd::make_cons, 0, 2}, // [3]: cons(#f,#nil)
|
||||||
|
|
||||||
|
// 1st gc
|
||||||
|
|
||||||
|
// ----- phase 1 -----
|
||||||
|
{Cmd::make_bool, 1, 0}, // [4]: #t
|
||||||
|
{Cmd::assign_head, 3, 4}, // set-car([3],#t)
|
||||||
|
|
||||||
|
// 2nd gc. [0]..[3] promote to g1
|
||||||
|
// [4] in g0 so [3]->[4] requires mlog entry
|
||||||
|
|
||||||
|
// ----- phase 2 -----
|
||||||
|
{Cmd::make_bool, 0, 0}, // [5]: #f
|
||||||
|
{Cmd::assign_head, 3, 5}, // set-car([3],#f)
|
||||||
|
|
||||||
|
// 3rd gc. [4] promotes to g1,
|
||||||
|
// [5] in g0 so [3]->[5] requires mlog entry
|
||||||
|
|
||||||
|
// ----- phase 3 -----
|
||||||
|
// ----- phase 4 -----
|
||||||
|
// ----- end -----
|
||||||
|
{Cmd::sentinel, 0, 0},
|
||||||
|
};
|
||||||
|
|
||||||
|
static Phase phase_4[] = {
|
||||||
|
//
|
||||||
|
// lo hi mlog_new_z_[]
|
||||||
|
// v v v
|
||||||
|
{ 0, 4, {0} }, // phase 0 gc
|
||||||
|
{ 4, 6, {1} }, // phase 1 gc. set-car makes 1x xage ptr
|
||||||
|
{ 6, 8, {2} }, // phase 2 gc. now src in g1, dest [4] in g0
|
||||||
|
{ 8, 8, {1} }, // phase 3 gc. new dest [5] in g0
|
||||||
|
{ 8, 8, {0} }, // phase 4 gc. now dest in g1
|
||||||
|
{ -1, -1, {0} },
|
||||||
|
};
|
||||||
|
|
||||||
|
static TestSequence seq_4 { step_4, phase_4 };
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------
|
||||||
|
|
||||||
# define seq_nil TestSequence{}
|
# define seq_nil TestSequence{}
|
||||||
# define nil nullptr
|
# define nil nullptr
|
||||||
# define T true
|
# define T true
|
||||||
|
|
@ -239,7 +284,8 @@ namespace ut {
|
||||||
Testcase(2, 4, 16 * 1024, 8 * 128, T, seq_0, 0, F, c_fixed, 1, 0, 0, 0, 0, F),
|
Testcase(2, 4, 16 * 1024, 8 * 128, T, seq_0, 0, F, c_fixed, 1, 0, 0, 0, 0, F),
|
||||||
Testcase(2, 4, 16 * 1024, 8 * 128, T, seq_1, 0, F, c_fixed, 1, 0, 0, 0, 0, F),
|
Testcase(2, 4, 16 * 1024, 8 * 128, T, seq_1, 0, F, c_fixed, 1, 0, 0, 0, 0, F),
|
||||||
Testcase(2, 1, 16 * 1024, 8 * 128, T, seq_2, 128, T, c_fixed, 3, 0, 0, 0, 0, F),
|
Testcase(2, 1, 16 * 1024, 8 * 128, T, seq_2, 128, T, c_fixed, 3, 0, 0, 0, 0, F),
|
||||||
Testcase(2, 2, 16 * 1024, 8 * 128, T, seq_3, 128, T, c_fixed, 4, 0, 0, 0, 0, T),
|
Testcase(2, 2, 16 * 1024, 8 * 128, T, seq_3, 128, T, c_fixed, 4, 0, 0, 0, 0, F),
|
||||||
|
Testcase(2, 2, 16 * 1024, 8 * 128, T, seq_4, 128, T, c_fixed, 4, 0, 0, 0, 0, T),
|
||||||
};
|
};
|
||||||
|
|
||||||
# undef T
|
# undef T
|
||||||
|
|
@ -376,6 +422,8 @@ namespace ut {
|
||||||
for (uint32_t loop_index = 0; loop_index < tc.n_gc_loop_; ++loop_index) {
|
for (uint32_t loop_index = 0; loop_index < tc.n_gc_loop_; ++loop_index) {
|
||||||
scope log2(XO_DEBUG(tc.debug_flag_), "gc loop", xtag("loop_index", loop_index));
|
scope log2(XO_DEBUG(tc.debug_flag_), "gc loop", xtag("loop_index", loop_index));
|
||||||
|
|
||||||
|
INFO(xtag("loop_index", loop_index));
|
||||||
|
|
||||||
GcosTestutil::gcos_construct_ab_object_graphs(tc.test_seq_,
|
GcosTestutil::gcos_construct_ab_object_graphs(tc.test_seq_,
|
||||||
tc.obj_graph_type_,
|
tc.obj_graph_type_,
|
||||||
tc.n_i0_test_obj_,
|
tc.n_i0_test_obj_,
|
||||||
|
|
@ -442,9 +490,8 @@ namespace ut {
|
||||||
|
|
||||||
REQUIRE(gcos.verify_stats()->is_ok());
|
REQUIRE(gcos.verify_stats()->is_ok());
|
||||||
}
|
}
|
||||||
}
|
} /*one gc cycle per loop*/
|
||||||
}
|
} /*testcase loop*/
|
||||||
|
|
||||||
}
|
}
|
||||||
} /*namespace ut*/
|
} /*namespace ut*/
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue