xo-allod: + per-type stats + pretty printing

This commit is contained in:
Roland Conybeare 2025-08-06 22:34:20 -05:00
commit 593dc064f9
16 changed files with 379 additions and 191 deletions

View file

@ -6,6 +6,7 @@
#pragma once
#include "IAlloc.hpp"
#include "ObjectStatistics.hpp"
namespace xo {
namespace gc {
@ -48,6 +49,9 @@ namespace xo {
std::byte * free_ptr() const { return free_ptr_; }
void set_free_ptr(std::byte * x);
void capture_object_statistics(capture_phase phase,
ObjectStatistics * p_dest) const;
// inherited from IAlloc...
virtual const std::string & name() const final override { return name_; }

View file

@ -13,6 +13,7 @@ namespace xo {
// inherited from Object..
virtual TaggedPtr self_tp() const final override;
virtual void display(std::ostream & os) const final override;
virtual bool _is_forwarded() const final override { return true; }
virtual Object * _offset_destination(Object * src) const final override;
virtual Object * _destination() final override;

View file

@ -42,6 +42,8 @@ namespace xo {
std::size_t initial_tenured_z_ = 0;
/** true to permit incremental garbage collection **/
bool allow_incremental_gc_ = true;
/** true to report statistics **/
bool stats_flag_ = false;
/** true to enable debug logging **/
bool debug_flag_ = false;
};
@ -207,6 +209,8 @@ namespace xo {
void swap_mutation_log();
/** swap roles of FromSpace/ToSpace **/
void swap_spaces(generation g);
/** scan to-space for object statistics before GC */
void capture_object_statistics(generation upto, capture_phase phase);
/** copy object **/
void copy_object(Object ** addr, generation upto, ObjectStatistics * object_stats);
/** copy everything reachable from global gc roots **/
@ -273,6 +277,10 @@ namespace xo {
/** allocation/collection counters **/
GcStatistics gc_statistics_;
/** optional per-object-type counters. snapshot at beginning of collection cycle **/
std::array<ObjectStatistics, gen2int(generation::N)> object_statistics_sab_;
/** optional per-object-type counters. snapshot at end of collection cycle **/
std::array<ObjectStatistics, gen2int(generation::N)> object_statistics_sae_;
/** trigger full GC whenever this much data arrives in tenured generation **/
std::size_t full_gc_threshold_ = 0;

View file

@ -6,20 +6,13 @@
#pragma once
#include "generation.hpp"
#include "xo/reflect/TypeDescr.hpp"
#include "xo/indentlog/print/pretty.hpp"
#include <ostream>
#include <array>
namespace xo {
namespace gc {
/** @class ObjectStatistics
* @brief placeholder for type-driven allocation statistics
*
* Passed to @ref Object::deep_move for example
**/
class ObjectStatistics {
};
/** @class PerGenerationStatistics
* @brief garbage collection statistics for particular GC generation
**/
@ -103,9 +96,6 @@ namespace xo {
* (N0 -> N1 when reported; cumulative across GCs)
**/
std::size_t n_xckp_mutation_ = 0;
/** per-type statistics (placeholder) **/
ObjectStatistics per_type_stats_;
};
inline std::ostream & operator<< (std::ostream & os, const GcStatistics & x) {

View file

@ -6,6 +6,7 @@
#pragma once
#include "IAlloc.hpp"
#include "ObjectStatistics.hpp"
#include <list>
#include <memory>
#include <cstdint>
@ -43,6 +44,14 @@ namespace xo {
/** current free pointer **/
std::byte * free_ptr() const;
/** scan space (must not contain forwarding pointers, because loses size info)
* + gather stats by object type
*
* See @ref Object::self_tp
**/
void capture_object_statistics(capture_phase phase,
ObjectStatistics * p_dest) const;
// inherited from IAlloc..
virtual const std::string & name() const final override;

View file

@ -157,6 +157,9 @@ namespace xo {
**/
virtual TaggedPtr self_tp() const = 0;
/** print on stream @p os **/
virtual void display(std::ostream & os) const = 0;
// GC support
/** true iff this object represents a forwarding pointer.
@ -244,6 +247,9 @@ namespace xo {
rhs.ptr());
}
std::ostream &
operator<< (std::ostream & os, gp<Object> x);
/** @class Cpof
* @brief argument to operator new used for garbage collector evacuation phase
*

View file

@ -0,0 +1,86 @@
/* file ObjectStatistics.hpp
*
* author: Roland Conybeare, Aug 2025
*/
#pragma once
#include "xo/indentlog/print/pretty.hpp"
#include <vector>
#include <cstdint>
namespace xo {
namespace reflect { class TypeDescrBase; }
namespace gc {
enum class capture_phase {
/** snapshot-at-beginning **/
sab,
/** snapshot-at-end **/
sae,
};
/** @class PerObjectTypeStatistics
* @brief statistics for a particular object type
*
* Gathered for each leaf type descended from xo::obj::Object.
* See @ref xo::obj::Object::self_tp
*
* See @ref GC::capture_object_statistics
* (gathers @ref scanned_n_, @ref scanned_z_)
**/
struct PerObjectTypeStatistics {
using TypeDescr = xo::reflect::TypeDescrBase const *;
void display(std::ostream & os) const;
/** stats here are for objects of this type **/
TypeDescr td_ = nullptr;
/** number of objects scanned **/
std::size_t scanned_n_ = 0;
/** number of bytes scanned **/
std::size_t scanned_z_ = 0;
/** number of objects surviving **/
std::size_t survive_n_ = 0;
/** number of bytes from surviving objects **/
std::size_t survive_z_ = 0;
};
inline std::ostream & operator<< (std::ostream & os, const PerObjectTypeStatistics & x) {
x.display(os);
return os;
}
/** @class ObjectStatistics
* @brief placeholder for type-driven allocation statistics
*
* Passed to @ref Object::deep_move for example
**/
struct ObjectStatistics {
void display(std::ostream & os) const;
/** per-object-type statistics, indexed by TypeId **/
std::vector<PerObjectTypeStatistics> per_type_stats_v_;
};
inline std::ostream & operator<< (std::ostream & os, const ObjectStatistics & x) {
x.display(os);
return os;
}
} /*namespace gc*/
namespace print {
template <>
struct ppdetail<xo::gc::PerObjectTypeStatistics> {
static bool print_pretty(const ppindentinfo &, const xo::gc::PerObjectTypeStatistics &);
};
template <>
struct ppdetail<xo::gc::ObjectStatistics> {
static bool print_pretty(const ppindentinfo &, const xo::gc::ObjectStatistics &);
};
} /*namespace print*/
} /*namespace xo*/
/* end ObjectStatistics.hpp */