From 0e6afabaa3101d0792928ef91df943b64e8d57e8 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Tue, 3 Feb 2026 11:55:50 -0500 Subject: [PATCH] xo-interpreter2 stack: cleanup memory reporting --- xo-arena/include/xo/arena/ArenaConfig.hpp | 8 ++++++- xo-arena/include/xo/arena/DArena.hpp | 2 +- xo-arena/include/xo/arena/DArenaHashMap.hpp | 6 +++-- xo-arena/include/xo/arena/DArenaVector.hpp | 22 ++++++++++++++++--- .../include/xo/arena/hashmap/HashMapStore.hpp | 6 +++-- xo-facet/include/xo/facet/FacetRegistry.hpp | 22 ++++++++++++++----- .../utest/VirtualSchematikaMachine.test.cpp | 2 ++ .../utest/interpreter2_utest_main.cpp | 5 +++++ .../include/xo/object2/init_object2.hpp | 2 +- xo-object2/src/object2/init_object2.cpp | 2 +- .../include/xo/reflectutil/typeseq.hpp | 6 ++++- 11 files changed, 66 insertions(+), 17 deletions(-) diff --git a/xo-arena/include/xo/arena/ArenaConfig.hpp b/xo-arena/include/xo/arena/ArenaConfig.hpp index 9ca2a387..d1ecbdca 100644 --- a/xo-arena/include/xo/arena/ArenaConfig.hpp +++ b/xo-arena/include/xo/arena/ArenaConfig.hpp @@ -31,6 +31,12 @@ namespace xo { return copy; } + ArenaConfig with_store_header_flag(bool x) const { + ArenaConfig copy(*this); + copy.store_header_flag_ = x; + return copy; + } + /** @defgroup mm-arenaconfig-instance-vars ArenaConfig members **/ ///@{ @@ -44,7 +50,7 @@ namespace xo { std::size_t hugepage_z_ = 2 * 1024 * 1024; /** true to store header (8 bytes) at the beginning of each allocation. * necessary and sufficient to allows iterating over allocs - * present in arena + * present in arena. **/ bool store_header_flag_ = false; /** configuration for per-alloc header **/ diff --git a/xo-arena/include/xo/arena/DArena.hpp b/xo-arena/include/xo/arena/DArena.hpp index 4c12c8cb..658d2b1b 100644 --- a/xo-arena/include/xo/arena/DArena.hpp +++ b/xo-arena/include/xo/arena/DArena.hpp @@ -205,7 +205,7 @@ namespace xo { void establish_initial_guard() noexcept; /** checkpoint arena state. Revert to the same state with - * @ref rstore + * @ref restore **/ Checkpoint checkpoint() noexcept { return Checkpoint(free_); } diff --git a/xo-arena/include/xo/arena/DArenaHashMap.hpp b/xo-arena/include/xo/arena/DArenaHashMap.hpp index c40f6926..c52b9894 100644 --- a/xo-arena/include/xo/arena/DArenaHashMap.hpp +++ b/xo-arena/include/xo/arena/DArenaHashMap.hpp @@ -30,8 +30,10 @@ namespace xo { * * Replicates (to the extent feasible) std::unordered_map * - * @tparam K key type. - * @tparam V value type. + * @tparam Key key type. + * @tparam Value value type. + * @tparam Hash hash function for keys + * @tparam Equal equality function for keys **/ template @@ -122,14 +123,16 @@ namespace xo { size_type arena_align_z, DArena::value_type lo, DArena::value_type hi) - : store_{cfg, page_z, arena_align_z, lo, hi} + : store_{cfg, page_z, arena_align_z, lo, hi}, + zero_ckp_{store_.checkpoint()} {} template DArenaVector::DArenaVector(DArenaVector && other) - : size_{other.size_}, store_{std::move(other.store_)} + : size_{other.size_}, store_{std::move(other.store_)}, zero_ckp_{std::move(other.zero_ckp_)} { other.size_ = 0; + other.zero_ckp_ = DArena::Checkpoint(); } template @@ -153,8 +156,10 @@ namespace xo { { this->size_ = other.size_; this->store_ = std::move(other.store_); + this->zero_ckp_ = std::move(other.zero_ckp_); other.size_ = 0; + other.zero_ckp_ = DArena::Checkpoint(); return *this; } @@ -166,6 +171,7 @@ namespace xo { DArenaVector retval; retval.store_ = std::move(DArena::map(cfg)); + retval.zero_ckp_ = retval.store_.checkpoint(); return retval; } @@ -179,9 +185,11 @@ namespace xo { template void DArenaVector::resize(size_type z) { + // new arena size in bytes + size_t req_z = z * sizeof(T); + if (z > size_) { // expand arena to accomodate - size_t req_z = z * sizeof(T); store_.expand(req_z); @@ -208,6 +216,14 @@ namespace xo { } } + // rewind to checkpoint, then reallocate. + // This is for form's sake, so that DArena considers memory + // to be 'allocated'. DArenaVector doesn't care for itself, + // but this preserves expected behavior of visit_pools(). + // + store_.restore(zero_ckp_); + store_.alloc(xo::reflect::typeseq::id(), req_z); + this->size_ = z; } diff --git a/xo-arena/include/xo/arena/hashmap/HashMapStore.hpp b/xo-arena/include/xo/arena/hashmap/HashMapStore.hpp index 34850222..436e88ed 100644 --- a/xo-arena/include/xo/arena/hashmap/HashMapStore.hpp +++ b/xo-arena/include/xo/arena/hashmap/HashMapStore.hpp @@ -33,11 +33,13 @@ namespace xo { control_{control_vector_type::map (xo::mm::ArenaConfig{ .name_ = name + "-ctl", - .size_ = control_size(n_slot_)})}, + .size_ = control_size(n_slot_), + .store_header_flag_ = false})}, slots_{slot_vector_type::map (xo::mm::ArenaConfig{ .name_ = name + "-slots", - .size_ = n_slot_ * sizeof(value_type)})} + .size_ = n_slot_ * sizeof(value_type), + .store_header_flag_ = false})} { /* here: arenas have allocated address range, but no committed memory yet */ diff --git a/xo-facet/include/xo/facet/FacetRegistry.hpp b/xo-facet/include/xo/facet/FacetRegistry.hpp index da3a6676..ad19cf53 100644 --- a/xo-facet/include/xo/facet/FacetRegistry.hpp +++ b/xo-facet/include/xo/facet/FacetRegistry.hpp @@ -10,6 +10,7 @@ #include "facet_implementation.hpp" #include "typeseq.hpp" #include "obj.hpp" +#include #include #include #include @@ -38,6 +39,7 @@ namespace xo { **/ class FacetRegistry { public: + using MemorySizeVisitor = xo::mm::MemorySizeVisitor; using typeseq = xo::reflect::typeseq; using key_type = std::pair; @@ -51,9 +53,12 @@ namespace xo { } }; - /** singleton instance **/ - static FacetRegistry & instance() { - static FacetRegistry s_instance; + /** singleton instance. + * @p hint_max_capacity is a lower bound for swiss hash map implementation. + * Only honored the first time instance is called. + **/ + static FacetRegistry & instance(uint32_t hint_max_capacity = 1024) { + static FacetRegistry s_instance(hint_max_capacity); return s_instance; } @@ -88,6 +93,11 @@ namespace xo { /** Number of registered (facet, repr) pairs **/ std::size_t size() const { return registry_.size(); } + /** visit memory pools owned by facet registry **/ + void visit_pools(const MemorySizeVisitor & visitor) { + registry_.visit_pools(visitor); + } + /** Check if implementation is registered **/ bool contains(typeseq facet_id, typeseq repr_id) const @@ -221,10 +231,12 @@ namespace xo { } private: - FacetRegistry() = default; + FacetRegistry(uint32_t hint_max_capacity) + : registry_("facets", hint_max_capacity, false /*!debug_flag*/) {} /** runtime lookup table (AFacet,DRepr) -> impl **/ - std::unordered_map registry_; + xo::map::DArenaHashMap registry_; + //std::unordered_map registry_; }; } /*namespace facet*/ diff --git a/xo-interpreter2/utest/VirtualSchematikaMachine.test.cpp b/xo-interpreter2/utest/VirtualSchematikaMachine.test.cpp index 2ad7122d..a4970b72 100644 --- a/xo-interpreter2/utest/VirtualSchematikaMachine.test.cpp +++ b/xo-interpreter2/utest/VirtualSchematikaMachine.test.cpp @@ -29,6 +29,7 @@ namespace xo { using xo::scm::DFloat; using xo::mm::AGCObject; using xo::mm::MemorySizeInfo; + using xo::facet::FacetRegistry; using span_type = xo::scm::VirtualSchematikaMachine::span_type; using Catch::Matchers::WithinAbs; @@ -84,6 +85,7 @@ namespace xo { xtag("resv", info.reserved_)); }; + FacetRegistry::instance().visit_pools(visitor); vsm.visit_pools(visitor); } diff --git a/xo-interpreter2/utest/interpreter2_utest_main.cpp b/xo-interpreter2/utest/interpreter2_utest_main.cpp index addc079a..ca898beb 100644 --- a/xo-interpreter2/utest/interpreter2_utest_main.cpp +++ b/xo-interpreter2/utest/interpreter2_utest_main.cpp @@ -3,6 +3,7 @@ * @author Roland Conybeare, Jan 2026 **/ +#include #include #define CATCH_CONFIG_RUNNER @@ -11,8 +12,12 @@ int main(int argc, char* argv[]) { + using xo::facet::FacetRegistry; using xo::Subsystem; + // initialize facet registry + FacetRegistry::instance(1024); + // initialize subsystems Subsystem::initialize_all(); diff --git a/xo-object2/include/xo/object2/init_object2.hpp b/xo-object2/include/xo/object2/init_object2.hpp index 5c26e76d..aa3dd510 100644 --- a/xo-object2/include/xo/object2/init_object2.hpp +++ b/xo-object2/include/xo/object2/init_object2.hpp @@ -1,5 +1,5 @@ /** @file init_object2.hpp -* + * * @author Roland Conybeare, Jan 2026 **/ diff --git a/xo-object2/src/object2/init_object2.cpp b/xo-object2/src/object2/init_object2.cpp index b5e57aba..0f804fe0 100644 --- a/xo-object2/src/object2/init_object2.cpp +++ b/xo-object2/src/object2/init_object2.cpp @@ -1,5 +1,5 @@ /** @file init_object2.cpp -* + * * @author Roland Conybeare, Jan 2026 **/ diff --git a/xo-reflectutil/include/xo/reflectutil/typeseq.hpp b/xo-reflectutil/include/xo/reflectutil/typeseq.hpp index dd0b869a..d2f888cd 100644 --- a/xo-reflectutil/include/xo/reflectutil/typeseq.hpp +++ b/xo-reflectutil/include/xo/reflectutil/typeseq.hpp @@ -16,6 +16,10 @@ namespace xo { */ template struct typeseq_impl { + /** create sentinel value **/ + typeseq_impl() = default; + + /** typeseq with specific unique id **/ explicit typeseq_impl(int32_t s) : seqno_{s} {} /** Can't have this be constexpr. @@ -56,7 +60,7 @@ namespace xo { private: static int32_t s_next_id; - int32_t seqno_; + int32_t seqno_ = 0; }; template