xo-alloc2: work on alloc iteration.
This commit is contained in:
parent
85204e9847
commit
d8ed0d6235
17 changed files with 216 additions and 29 deletions
|
|
@ -14,9 +14,6 @@ namespace xo {
|
|||
using Copaque = const void *;
|
||||
using Opaque = void *;
|
||||
|
||||
/** forward decl for obj<AAllocIterator> **/
|
||||
struct ObjAllocIterator;
|
||||
|
||||
/** @class AAllocIterator
|
||||
* @brief Abstract facet for iterating over allocs
|
||||
*
|
||||
|
|
|
|||
|
|
@ -16,6 +16,9 @@ namespace xo {
|
|||
using Copaque = const void *;
|
||||
using Opaque = void *;
|
||||
|
||||
// see DArena.hpp
|
||||
struct DArena;
|
||||
|
||||
/** @class AAllocator
|
||||
* @brief Abstract facet for allocation
|
||||
*
|
||||
|
|
@ -81,7 +84,21 @@ namespace xo {
|
|||
*
|
||||
* Non-const @p d because may stash error details
|
||||
**/
|
||||
virtual AllocInfo alloc_info(Opaque d, value_type mem) const noexcept = 0;
|
||||
virtual AllocInfo alloc_info(Copaque d, value_type mem) const noexcept = 0;
|
||||
/** Ideally we want to control allocation for iterator here.
|
||||
* Awkward to describe to compiler since we don't have vt<AAllocator> yet.
|
||||
* OTOH iteration over allocs is a niche feature.
|
||||
* Consider alternatives:
|
||||
* - put begin/end in separate interface. e.g. extend AAllocator
|
||||
* - layer of indirection: begin/end return iterator factory.
|
||||
* Then allocator can be passed to iterator factory separately.
|
||||
* Helps because factory can be static
|
||||
* - abandon allocator support in this case. Instead will need to
|
||||
* reinstate uvt<AAllocIterator> (unique variant), use heap
|
||||
* - just pass DArena& for alloc-iterator-allocation
|
||||
**/
|
||||
//virtual facet::vt<AAllocIterator> begin(Copaque d, DArena & ialloc) const noexcept;
|
||||
// virtual obj<AAllocIterator> end() const noexcept = 0;
|
||||
|
||||
/** expand committed space in arena @p d
|
||||
* to size at least @p z
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@
|
|||
#pragma once
|
||||
|
||||
#include "AAllocator.hpp"
|
||||
#include "AllocIterator.hpp"
|
||||
#include <xo/facet/obj.hpp>
|
||||
#include <cassert>
|
||||
|
||||
namespace xo {
|
||||
|
|
@ -40,9 +42,11 @@ namespace xo {
|
|||
[[noreturn]] size_type allocated(Copaque) const noexcept override { _fatal(); }
|
||||
[[noreturn]] bool contains(Copaque, const void *) const noexcept override { _fatal(); }
|
||||
[[noreturn]] AllocError last_error(Copaque) const noexcept override { _fatal(); }
|
||||
[[noreturn]] AllocInfo alloc_info(Copaque, value_type) const noexcept override { _fatal(); }
|
||||
// defn in .cpp - problematic to require compiler know vt<AAllocIterator> defn here
|
||||
//[[noreturn]] facet::vt<AAllocIterator> begin(Copaque, DArena &) const noexcept override; // { _fatal(); }
|
||||
|
||||
// non-const methods
|
||||
[[noreturn]] AllocInfo alloc_info(Opaque, value_type) const noexcept override { _fatal(); }
|
||||
[[noreturn]] bool expand(Opaque, std::size_t) const noexcept override { _fatal(); }
|
||||
[[noreturn]] value_type alloc(Opaque, std::size_t) const override { _fatal(); }
|
||||
[[noreturn]] value_type super_alloc(Opaque, std::size_t) const override { _fatal(); }
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ namespace xo {
|
|||
|
||||
// non-const methods
|
||||
|
||||
AllocInfo alloc_info(Opaque d, value_type mem) const noexcept override {
|
||||
AllocInfo alloc_info(Copaque d, value_type mem) const noexcept override {
|
||||
return I::alloc_info(_dcast(d), mem);
|
||||
}
|
||||
bool expand(Opaque d,
|
||||
|
|
|
|||
|
|
@ -22,6 +22,10 @@ namespace xo {
|
|||
RAllocIterator(Object::DataPtr data) : Object{std::move(data)} {}
|
||||
|
||||
int32_t _typeseq() const noexcept { return O::iface()->_typeseq(); }
|
||||
AllocInfo deref() const noexcept { return O::iface()->deref(O::data()); }
|
||||
cmpresult compare(const obj<AAllocIterator> & other) const noexcept {
|
||||
return O::iface()->compare(O::data(), other); }
|
||||
void next() noexcept { O::iface()->next(O::data()); }
|
||||
|
||||
static bool _valid;
|
||||
};
|
||||
|
|
@ -36,6 +40,21 @@ namespace xo {
|
|||
struct RoutingFor<xo::mm::AAllocIterator, Object> {
|
||||
using RoutingType = xo::mm::RAllocIterator<Object>;
|
||||
};
|
||||
|
||||
/* also provide comparison */
|
||||
template <typename DRepr1, typename DRepr2>
|
||||
inline bool operator==(obj<xo::mm::AAllocIterator, DRepr1> lhs,
|
||||
obj<xo::mm::AAllocIterator, DRepr2> rhs)
|
||||
{
|
||||
return lhs.compare(rhs).is_equal();
|
||||
}
|
||||
|
||||
template <typename DRepr1, typename DRepr2>
|
||||
inline bool operator!=(obj<xo::mm::AAllocIterator, DRepr1> lhs,
|
||||
obj<xo::mm::AAllocIterator, DRepr2> rhs)
|
||||
{
|
||||
return !lhs.compare(rhs).is_equal();
|
||||
}
|
||||
}
|
||||
} /*namespace xo*/
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "AAllocator.hpp"
|
||||
#include "AllocIterator.hpp"
|
||||
#include <xo/facet/RRouter.hpp>
|
||||
#include <string>
|
||||
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ namespace xo {
|
|||
static AllocError last_error(const DArena &) noexcept;
|
||||
|
||||
/** retrieve allocation bookkeeping info for @p mem from arena @p d **/
|
||||
static AllocInfo alloc_info(DArena &, value_type mem) noexcept;
|
||||
static AllocInfo alloc_info(const DArena &, value_type mem) noexcept;
|
||||
/** expand committed space in arena @p d
|
||||
* to size at least @p z
|
||||
* In practice will round up to a multiple of @ref page_z_.
|
||||
|
|
|
|||
|
|
@ -46,7 +46,12 @@ namespace xo {
|
|||
/** print to stream **/
|
||||
void display(std::ostream & os) const;
|
||||
|
||||
bool is_equal() const { return (err_ == comparison::comparable) && (cmp_ == 0); }
|
||||
bool is_lesser() const {
|
||||
return (err_ == comparison::comparable) && (cmp_ < 0);
|
||||
}
|
||||
bool is_equal() const {
|
||||
return (err_ == comparison::comparable) && (cmp_ == 0);
|
||||
}
|
||||
|
||||
/* -1 -> invalid (sentinel)
|
||||
* 0 -> comparable
|
||||
|
|
|
|||
|
|
@ -191,6 +191,9 @@ namespace xo {
|
|||
/** true iff original alloc has been replaced by a forwarding pointer **/
|
||||
bool is_forwarding_header(header_type hdr) const noexcept;
|
||||
|
||||
/** Retreive bookkeeping info for allocation at @p mem. **/
|
||||
AllocInfo alloc_info(value_type mem) const noexcept;
|
||||
|
||||
// ----- allocation -----
|
||||
|
||||
/** simple allocation. new allocs always in gen0 to-space **/
|
||||
|
|
@ -211,8 +214,6 @@ namespace xo {
|
|||
/** expand gen0 committed size to at least @p z.
|
||||
**/
|
||||
bool expand(size_type z) noexcept;
|
||||
/** Retreive bookkeeping info for allocation at @p mem. **/
|
||||
AllocInfo alloc_info(value_type mem) noexcept;
|
||||
|
||||
// ----- iteration -----
|
||||
|
||||
|
|
|
|||
|
|
@ -42,6 +42,11 @@ namespace xo {
|
|||
bool is_valid() const noexcept { return (gc_ != nullptr); }
|
||||
bool is_invalid() const noexcept { return !is_valid(); }
|
||||
|
||||
generation gen_ix() const { return gen_ix_; }
|
||||
generation gen_hi() const { return gen_hi_; }
|
||||
DArenaIterator arena_ix() const { return arena_ix_; }
|
||||
DArenaIterator arena_hi() const { return arena_hi_; }
|
||||
|
||||
/** fetch contents at current iterator position **/
|
||||
AllocInfo deref() const noexcept;
|
||||
/** compare two iterators. To be comparable,
|
||||
|
|
|
|||
|
|
@ -49,6 +49,8 @@ namespace xo {
|
|||
static bool contains(const DX1Collector & d, const void * p) noexcept;
|
||||
/** report last error, if any, for collector @p d **/
|
||||
static AllocError last_error(const DX1Collector &) noexcept;
|
||||
/** fetch allocation bookkeeping info **/
|
||||
static AllocInfo alloc_info(const DX1Collector & d, value_type mem) noexcept;
|
||||
|
||||
/** always alloc in gen0 to-space **/
|
||||
static value_type alloc(DX1Collector & d, size_type z) noexcept;
|
||||
|
|
@ -56,8 +58,6 @@ namespace xo {
|
|||
static value_type sub_alloc(DX1Collector & d, size_type z, bool complete) noexcept;
|
||||
/** expand gen0 spaces (both from-space and to-space) **/
|
||||
static bool expand(DX1Collector & d, size_type z) noexcept;
|
||||
/** fetch allocation bookkeeping info **/
|
||||
static AllocInfo alloc_info(DX1Collector & d, value_type mem) noexcept;
|
||||
|
||||
/** reset to empty state; clears all generations **/
|
||||
static void clear(DX1Collector & d);
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
#include "gc/generation.hpp"
|
||||
#include "gc/object_age.hpp"
|
||||
#include <xo/facet/obj.hpp>
|
||||
#include <xo/indentlog/scope.hpp>
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
|
||||
|
|
@ -207,10 +208,10 @@ namespace xo {
|
|||
}
|
||||
|
||||
AllocInfo
|
||||
DX1Collector::alloc_info(value_type mem) noexcept {
|
||||
DX1Collector::alloc_info(value_type mem) const noexcept {
|
||||
for (role ri : role::all()) {
|
||||
for (generation gj{0}; gj < config_.n_generation_; ++gj) {
|
||||
DArena * arena = this->get_space(ri, gj);
|
||||
const DArena * arena = this->get_space(ri, gj);
|
||||
|
||||
assert(arena);
|
||||
|
||||
|
|
@ -221,21 +222,29 @@ namespace xo {
|
|||
}
|
||||
|
||||
// deliberately attempt on nursery to-space, to capture error info + return sentinel
|
||||
return this->new_space()->alloc_info(mem);
|
||||
return this->get_space(role::to_space(), generation{0})->alloc_info(mem);
|
||||
}
|
||||
|
||||
DX1CollectorIterator
|
||||
DX1Collector::begin() const noexcept
|
||||
{
|
||||
scope log(XO_DEBUG(false));
|
||||
|
||||
const DArena * arena
|
||||
= get_space(role::to_space(),
|
||||
generation{0});
|
||||
|
||||
return DX1CollectorIterator(this,
|
||||
generation{0},
|
||||
generation{config_.n_generation_},
|
||||
DArenaIterator(),
|
||||
DArenaIterator());
|
||||
arena->begin(),
|
||||
arena->end());
|
||||
}
|
||||
|
||||
DX1CollectorIterator
|
||||
DX1Collector::end() const noexcept {
|
||||
scope log(XO_DEBUG(false));
|
||||
|
||||
generation gen_hi = generation{config_.n_generation_};
|
||||
|
||||
/** valid iterator for end points to end of last DArena.
|
||||
|
|
|
|||
|
|
@ -26,19 +26,39 @@ namespace xo {
|
|||
void
|
||||
DX1CollectorIterator::normalize() noexcept
|
||||
{
|
||||
scope log(XO_DEBUG(false),
|
||||
xtag("gen_ix", gen_ix_),
|
||||
xtag("gen_hi", gen_hi_),
|
||||
xtag("arena_ix.pos", arena_ix_.pos_),
|
||||
xtag("arena_hi.pos", arena_hi_.pos_));
|
||||
|
||||
/* normalize: find lowest generation with non-empty to-space */
|
||||
if (arena_ix_.pos_ == arena_hi_.pos_) {
|
||||
log && log(xtag("action", "look-lub-nonempty-gen"));
|
||||
|
||||
for (; gen_ix_ < gen_hi_; ++gen_ix_) {
|
||||
const DArena * arena
|
||||
= gc_->get_space(role::to_space(), gen_ix_);
|
||||
if (gen_ix_ < gen_hi_)
|
||||
++gen_ix_;
|
||||
|
||||
arena_ix_ = arena->begin();
|
||||
arena_hi_ = arena->end();
|
||||
for (; gen_ix_ < gen_hi_; ++gen_ix_) {
|
||||
const DArena * arena
|
||||
= gc_->get_space(role::to_space(), gen_ix_);
|
||||
|
||||
if (arena_ix_ != arena_hi_) {
|
||||
// normalization achieved!
|
||||
break;
|
||||
assert(arena);
|
||||
|
||||
arena_ix_ = arena->begin();
|
||||
arena_hi_ = arena->end();
|
||||
|
||||
if (arena_ix_ != arena_hi_) {
|
||||
// normalization achieved!
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
log && log(xtag("gen_ix", gen_ix_),
|
||||
xtag("arena_ix.pos", arena_ix_.pos_),
|
||||
xtag("arena_hi.pos", arena_hi_.pos_));
|
||||
} else {
|
||||
log && log(xtag("action", "noop"));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -81,9 +101,23 @@ namespace xo {
|
|||
void
|
||||
DX1CollectorIterator::next() noexcept
|
||||
{
|
||||
scope log(XO_DEBUG(false),
|
||||
xtag("arena_ix.arena", arena_ix_.arena_),
|
||||
xtag("arena_ix.pos", arena_ix_.pos_),
|
||||
xtag("arena_hi.arena", arena_hi_.arena_),
|
||||
xtag("arena_hi.pos", arena_hi_.pos_));
|
||||
|
||||
if (arena_ix_ != arena_hi_) {
|
||||
++arena_ix_;
|
||||
|
||||
log && log(xtag("++arena_ix.pos", arena_ix_.pos_));
|
||||
|
||||
this->normalize();
|
||||
|
||||
log && log(xtag("arena_ix.arena", arena_ix_.arena_),
|
||||
xtag("arena_ix.pos", arena_ix_.pos_));
|
||||
} else {
|
||||
log && log(xtag("action", "arena-at-end"));
|
||||
}
|
||||
}
|
||||
} /*namespace mm*/
|
||||
|
|
|
|||
|
|
@ -27,6 +27,14 @@ namespace xo {
|
|||
std::terminate();
|
||||
}
|
||||
|
||||
#ifdef NOPE
|
||||
vt<AAllocIterator>
|
||||
IAllocator_Any::begin(Copaque, DArena &) const noexcept
|
||||
{
|
||||
_fatal();
|
||||
}
|
||||
#endif
|
||||
|
||||
int32_t
|
||||
IAllocator_Any::s_typeseq = typeseq::id<DVariantPlaceholder>();
|
||||
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ namespace xo {
|
|||
}
|
||||
|
||||
AllocInfo
|
||||
IAllocator_DArena::alloc_info(DArena & s, value_type mem) noexcept
|
||||
IAllocator_DArena::alloc_info(const DArena & s, value_type mem) noexcept
|
||||
{
|
||||
return s.alloc_info(mem);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -86,7 +86,7 @@ namespace xo {
|
|||
}
|
||||
|
||||
AllocInfo
|
||||
IAllocator_DX1Collector::alloc_info(DX1Collector & d, value_type mem) noexcept
|
||||
IAllocator_DX1Collector::alloc_info(const DX1Collector & d, value_type mem) noexcept
|
||||
{
|
||||
return d.alloc_info(mem);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,8 @@
|
|||
#include "gc/IAllocIterator_DX1CollectorIterator.hpp"
|
||||
#include "arena/ArenaConfig.hpp"
|
||||
#include "padding.hpp"
|
||||
#include <xo/indentlog/scope.hpp>
|
||||
#include <xo/indentlog/print/tag.hpp>
|
||||
#include <catch2/catch.hpp>
|
||||
|
||||
namespace xo {
|
||||
|
|
@ -22,6 +24,10 @@ namespace xo {
|
|||
using xo::mm::CollectorConfig;
|
||||
using xo::mm::ArenaConfig;
|
||||
using xo::mm::AllocHeaderConfig;
|
||||
using xo::mm::cmpresult;
|
||||
using xo::mm::padding;
|
||||
using xo::facet::with_facet;
|
||||
using std::byte;
|
||||
|
||||
namespace ut {
|
||||
TEST_CASE("IAllocIterator_Xfer_DX1CollectorIterator", "[alloc2]")
|
||||
|
|
@ -31,7 +37,7 @@ namespace xo {
|
|||
REQUIRE(IAllocIterator_Xfer<DX1CollectorIterator, IAllocIterator_DX1CollectorIterator>::_valid);
|
||||
}
|
||||
|
||||
TEST_CASE("DX1CollectorIterator", "[alloc2][gc][DX1Collector]")
|
||||
TEST_CASE("DX1CollectorIterator-1", "[alloc2][gc][DX1Collector]")
|
||||
{
|
||||
ArenaConfig arena_cfg = { .name_ = "_test_unused",
|
||||
.size_ = 4*1024*1024,
|
||||
|
|
@ -55,8 +61,89 @@ namespace xo {
|
|||
|
||||
REQUIRE(ix.is_valid());
|
||||
REQUIRE(end_ix.is_valid());
|
||||
|
||||
REQUIRE(ix == end_ix);
|
||||
|
||||
/* verify obj 'fat pointer' packaging */
|
||||
obj<AAllocIterator,DX1CollectorIterator> ix_vt{&ix};
|
||||
obj<AAllocIterator,DX1CollectorIterator> end_ix_vt{&end_ix};
|
||||
|
||||
REQUIRE(ix_vt.iface());
|
||||
REQUIRE(ix_vt.data());
|
||||
REQUIRE(end_ix_vt.iface());
|
||||
REQUIRE(end_ix_vt.data());
|
||||
|
||||
cmpresult cmp = ix_vt.compare(end_ix_vt);
|
||||
|
||||
REQUIRE(cmp.is_equal());
|
||||
REQUIRE(ix_vt == end_ix_vt);
|
||||
}
|
||||
|
||||
TEST_CASE("DX1CollectorIterator-2", "[alloc2][gc][DX1Collector]")
|
||||
{
|
||||
scope log(XO_DEBUG(false));
|
||||
|
||||
ArenaConfig arena_cfg = { .name_ = "_test_unused",
|
||||
.size_ = 4*1024*1024,
|
||||
.store_header_flag_ = true,
|
||||
.header_ = AllocHeaderConfig(0 /*guard_z*/,
|
||||
0xfd /*guard_byte*/,
|
||||
0 /*tseq_bits*/,
|
||||
0 /*age_bits*/,
|
||||
16 /*size_bits*/), };
|
||||
CollectorConfig cfg = { .arena_config_ = arena_cfg,
|
||||
.n_generation_ = 2,
|
||||
.gc_trigger_v_ = {{64*1024, 1024*1024, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0}} };
|
||||
|
||||
DX1Collector gc = DX1Collector{cfg};
|
||||
|
||||
size_t z = 13;
|
||||
byte * mem = gc.alloc(z);
|
||||
|
||||
REQUIRE(mem != nullptr);
|
||||
|
||||
log && log("should have iterators separated by one alloc");
|
||||
|
||||
auto ix = gc.begin();
|
||||
auto end_ix = gc.end();
|
||||
|
||||
REQUIRE(ix.is_valid());
|
||||
REQUIRE(end_ix.is_valid());
|
||||
REQUIRE(ix != end_ix);
|
||||
|
||||
/* verify obj 'fat pointer' packaging */
|
||||
auto ix_vt = with_facet<AAllocIterator>::mkobj(&ix);
|
||||
auto end_ix_vt = with_facet<AAllocIterator>::mkobj(&end_ix);
|
||||
|
||||
REQUIRE(ix_vt.iface());
|
||||
REQUIRE(ix_vt.data());
|
||||
REQUIRE(end_ix_vt.iface());
|
||||
REQUIRE(end_ix_vt.data());
|
||||
|
||||
cmpresult cmp = ix_vt.compare(end_ix_vt);
|
||||
|
||||
REQUIRE(cmp.is_lesser());
|
||||
REQUIRE(ix_vt != end_ix_vt);
|
||||
|
||||
/* we only did one alloc, should be able
|
||||
* to visit it
|
||||
*/
|
||||
auto info = ix_vt.deref();
|
||||
|
||||
REQUIRE(info.is_valid());
|
||||
REQUIRE(info.payload().first == mem);
|
||||
REQUIRE(info.size() == padding::with_padding(z));
|
||||
|
||||
ix_vt.next();
|
||||
|
||||
log && log(xtag("ix.gen", ix.gen_ix()),
|
||||
xtag("ix.arena_ix.arena", ix.arena_ix().arena_));
|
||||
log && log(xtag("end_ix.gen", end_ix.gen_ix()),
|
||||
xtag("end_ix.arena_ix.arena", end_ix.arena_ix().arena_));
|
||||
|
||||
REQUIRE(ix_vt == end_ix_vt);
|
||||
}
|
||||
} /*namespace ut*/
|
||||
} /*namespace xo*/
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue