xo-object: improve GC unittest + prep to integrate w/ xo::reflect
This commit is contained in:
parent
ff5b0cfb8a
commit
432e0efce2
8 changed files with 305 additions and 120 deletions
|
|
@ -6,6 +6,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "ListAlloc.hpp"
|
||||
#include "GcStatistics.hpp"
|
||||
#include "xo/indentlog/print/array.hpp"
|
||||
#include <vector>
|
||||
#include <array>
|
||||
|
|
@ -15,20 +16,6 @@ namespace xo {
|
|||
class Object;
|
||||
|
||||
namespace gc {
|
||||
enum class generation {
|
||||
nursery,
|
||||
tenured,
|
||||
N
|
||||
};
|
||||
|
||||
constexpr std::size_t gen2int(generation x) { return static_cast<std::size_t>(x); }
|
||||
|
||||
enum class generation_result {
|
||||
nursery,
|
||||
tenured,
|
||||
not_found
|
||||
};
|
||||
|
||||
enum class role {
|
||||
/** nursery: generation for new objects **/
|
||||
from_space,
|
||||
|
|
@ -59,104 +46,6 @@ namespace xo {
|
|||
bool debug_flag_ = false;
|
||||
};
|
||||
|
||||
/** @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
|
||||
**/
|
||||
class PerGenerationStatistics {
|
||||
public:
|
||||
/** update statistics after a GC cycle
|
||||
* @param alloc_z. new allocations (since preceding GC)
|
||||
* @param before_z. generation size (bytes allocated) before collection
|
||||
* @param after_z. generation size after collection
|
||||
* @param promote_z. bytes promoted to next generation
|
||||
**/
|
||||
void include_gc(std::size_t alloc_z, std::size_t before_z, std::size_t after_z,
|
||||
std::size_t promote_z);
|
||||
/** update with current state (use at end of gc cycle) **/
|
||||
void update_snapshot(std::size_t after_z);
|
||||
|
||||
/** @param os. write stats on this output stream **/
|
||||
void display(std::ostream & os) const;
|
||||
|
||||
/** number of bytes currently in use **/
|
||||
std::size_t used_z_ = 0;
|
||||
|
||||
/** number of collection cycles completed **/
|
||||
std::size_t n_gc_ = 0;
|
||||
/** sum of new alloc bytes, sampled at start of each collection cycle **/
|
||||
std::size_t new_alloc_z_ = 0;
|
||||
/** sum of allocated bytes sampled at beginning of each collection cycle **/
|
||||
std::size_t scanned_z_ = 0;
|
||||
/** sum of bytes remaining after collection cycle **/
|
||||
std::size_t survive_z_ = 0;
|
||||
/** sum of bytes promoted to next generation **/
|
||||
std::size_t promote_z_ = 0;
|
||||
};
|
||||
|
||||
inline std::ostream & operator<< (std::ostream & os, const PerGenerationStatistics & x) {
|
||||
x.display(os);
|
||||
return os;
|
||||
}
|
||||
|
||||
/** @class GcStatistics
|
||||
* @brief garbage collection statistics
|
||||
**/
|
||||
class GcStatistics {
|
||||
public:
|
||||
/** update statistics after a GC cycle
|
||||
* @param upto. nursery -> incremental collection; tenured -> full collection
|
||||
* @param alloc_z. new allocations (since preceding GC)
|
||||
* @param before_z. generation size (bytes allocated) before collection
|
||||
* @param after_z. generation size after collection
|
||||
* @param promote_z. bytes promoted to next generation
|
||||
**/
|
||||
void include_gc(generation upto, std::size_t alloc_z,
|
||||
std::size_t before_z, std::size_t after_z, std::size_t promote_z);
|
||||
/** update snapshot for current state.
|
||||
* Use with tenured stats after incremental gc
|
||||
**/
|
||||
void update_snapshot(generation upto, std::size_t after_z);
|
||||
|
||||
/** @param os. write stats on this output stream **/
|
||||
void display(std::ostream & os) const;
|
||||
|
||||
/** statistics gathered across {incr, full} GCs respectively **/
|
||||
std::array<PerGenerationStatistics, static_cast<std::size_t>(generation::N)> gen_v_;
|
||||
/** total bytes allocated since inception **/
|
||||
std::size_t total_allocated_ = 0;
|
||||
/** snapshot of total bytes promoted asof beginning of last gc cycle **/
|
||||
std::size_t total_promoted_sab_ = 0;
|
||||
/** total bytes promoted from nursery->tenured since inception **/
|
||||
std::size_t total_promoted_ = 0;
|
||||
|
||||
/** total number of mutations to already-allocated objects,
|
||||
* whether or not GC needs to log them.
|
||||
**/
|
||||
std::size_t n_mutation_ = 0;
|
||||
/** total number of mutation eligible for logging **/
|
||||
std::size_t n_logged_mutation_ = 0;
|
||||
/** total number of cross-generation mutations (tenured->nursery when reported) **/
|
||||
std::size_t n_xgen_mutation_ = 0;
|
||||
/** total number of cross-checkpoint mutations (N0 -> N1 when reported) **/
|
||||
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) {
|
||||
x.display(os);
|
||||
return os;
|
||||
}
|
||||
|
||||
/** @class GCRunstate
|
||||
* @brief encapsulate state needed while GC is running
|
||||
*
|
||||
|
|
@ -228,7 +117,8 @@ namespace xo {
|
|||
static up<GC> make(const Config & config);
|
||||
|
||||
const GCRunstate & runstate() const { return runstate_; }
|
||||
const GcStatistics & gc_statistics() const { return gc_statistics_; }
|
||||
const GcStatistics & native_gc_statistics() const { return gc_statistics_; }
|
||||
GcStatisticsExt get_gc_statistics() const;
|
||||
|
||||
/** true iff GC permitted in current state **/
|
||||
bool is_gc_enabled() const { return gc_enabled_ == 0; }
|
||||
|
|
|
|||
161
include/xo/alloc/GcStatistics.hpp
Normal file
161
include/xo/alloc/GcStatistics.hpp
Normal file
|
|
@ -0,0 +1,161 @@
|
|||
/* GcStatistics.hpp
|
||||
*
|
||||
* author: Roland Conybeare, Aug 2025
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "generation.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
|
||||
**/
|
||||
class PerGenerationStatistics {
|
||||
public:
|
||||
/** update statistics after a GC cycle
|
||||
* @param alloc_z. new allocations (since preceding GC)
|
||||
* @param before_z. generation size (bytes allocated) before collection
|
||||
* @param after_z. generation size after collection
|
||||
* @param promote_z. bytes promoted to next generation
|
||||
**/
|
||||
void include_gc(std::size_t alloc_z, std::size_t before_z, std::size_t after_z,
|
||||
std::size_t promote_z);
|
||||
/** update with current state (use at end of gc cycle) **/
|
||||
void update_snapshot(std::size_t after_z);
|
||||
|
||||
/** @param os. write stats on this output stream **/
|
||||
void display(std::ostream & os) const;
|
||||
|
||||
/** number of bytes currently in use **/
|
||||
std::size_t used_z_ = 0;
|
||||
|
||||
/** number of collection cycles completed **/
|
||||
std::size_t n_gc_ = 0;
|
||||
/** sum of new alloc bytes, sampled at start of each collection cycle **/
|
||||
std::size_t new_alloc_z_ = 0;
|
||||
/** sum of allocated bytes sampled at beginning of each collection cycle **/
|
||||
std::size_t scanned_z_ = 0;
|
||||
/** sum of bytes remaining after collection cycle **/
|
||||
std::size_t survive_z_ = 0;
|
||||
/** sum of bytes promoted to next generation **/
|
||||
std::size_t promote_z_ = 0;
|
||||
};
|
||||
|
||||
inline std::ostream & operator<< (std::ostream & os, const PerGenerationStatistics & x) {
|
||||
x.display(os);
|
||||
return os;
|
||||
}
|
||||
|
||||
/** @class GcStatistics
|
||||
* @brief garbage collection statistics
|
||||
**/
|
||||
class GcStatistics {
|
||||
public:
|
||||
/** update statistics after a GC cycle
|
||||
* @param upto. nursery -> incremental collection; tenured -> full collection
|
||||
* @param alloc_z. new allocations (since preceding GC)
|
||||
* @param before_z. generation size (bytes allocated) before collection
|
||||
* @param after_z. generation size after collection
|
||||
* @param promote_z. bytes promoted to next generation
|
||||
**/
|
||||
void include_gc(generation upto, std::size_t alloc_z,
|
||||
std::size_t before_z, std::size_t after_z, std::size_t promote_z);
|
||||
/** update snapshot for current state.
|
||||
* Use with tenured stats after incremental gc
|
||||
**/
|
||||
void update_snapshot(generation upto, std::size_t after_z);
|
||||
|
||||
/** @param os. write stats on this output stream **/
|
||||
void display(std::ostream & os) const;
|
||||
|
||||
/** statistics gathered across {incr, full} GCs respectively **/
|
||||
std::array<PerGenerationStatistics, static_cast<std::size_t>(generation::N)> gen_v_;
|
||||
/** total bytes allocated since inception **/
|
||||
std::size_t total_allocated_ = 0;
|
||||
/** snapshot of total bytes promoted asof beginning of last gc cycle **/
|
||||
std::size_t total_promoted_sab_ = 0;
|
||||
/** total bytes promoted from nursery->tenured since inception **/
|
||||
std::size_t total_promoted_ = 0;
|
||||
|
||||
/** total number of mutations to already-allocated objects,
|
||||
* whether or not GC needs to log them.
|
||||
**/
|
||||
std::size_t n_mutation_ = 0;
|
||||
/** total number of mutation eligible for logging (cumulative across GCs) **/
|
||||
std::size_t n_logged_mutation_ = 0;
|
||||
/** total number of cross-generation mutations
|
||||
* (tenured->nursery when reported; cumulative across GCs) **/
|
||||
std::size_t n_xgen_mutation_ = 0;
|
||||
/** total number of cross-checkpoint mutations
|
||||
* (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) {
|
||||
x.display(os);
|
||||
return os;
|
||||
}
|
||||
|
||||
/** @class GcStatisticsExt
|
||||
* @brief extend GcStatistics for application convenience
|
||||
**/
|
||||
class GcStatisticsExt : public GcStatistics {
|
||||
public:
|
||||
explicit GcStatisticsExt(const GcStatistics & x) : GcStatistics{x} {}
|
||||
|
||||
/** @param os. write stats on this output stream **/
|
||||
void display(std::ostream & os) const;
|
||||
|
||||
/** current capacity of nursery generation **/
|
||||
std::size_t nursery_z_ = 0;
|
||||
/** current nursery survivor size **/
|
||||
std::size_t nursery_before_checkpoint_z_ = 0;
|
||||
/** current nursery new alloc size **/
|
||||
std::size_t nursery_after_checkpoint_z_ = 0;
|
||||
/** current capacity of tenured generation **/
|
||||
std::size_t tenured_z_ = 0;
|
||||
};
|
||||
|
||||
inline std::ostream & operator<< (std::ostream & os, const GcStatisticsExt & x) {
|
||||
x.display(os);
|
||||
return os;
|
||||
}
|
||||
|
||||
} /*namespace gc*/
|
||||
|
||||
namespace print {
|
||||
template <>
|
||||
struct ppdetail<xo::gc::PerGenerationStatistics> {
|
||||
static bool print_pretty(const ppindentinfo &, const xo::gc::PerGenerationStatistics &);
|
||||
};
|
||||
|
||||
template<>
|
||||
struct ppdetail<xo::gc::GcStatistics> {
|
||||
static bool print_pretty(const ppindentinfo &, const xo::gc::GcStatistics &);
|
||||
};
|
||||
|
||||
template<>
|
||||
struct ppdetail<xo::gc::GcStatisticsExt> {
|
||||
static bool print_pretty(const ppindentinfo &, const xo::gc::GcStatisticsExt &);
|
||||
};
|
||||
} /*namespace print*/
|
||||
} /*namespace xo*/
|
||||
|
||||
/* end GcStatistics.hpp */
|
||||
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "xo/reflect/SelfTagging.hpp"
|
||||
#include "IAlloc.hpp"
|
||||
#include <concepts>
|
||||
#include <cstdint>
|
||||
|
|
|
|||
26
include/xo/alloc/generation.hpp
Normal file
26
include/xo/alloc/generation.hpp
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
/* generation.hpp
|
||||
*
|
||||
* author: Roland Conybeare, Aug 2025
|
||||
*/
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace xo {
|
||||
namespace gc {
|
||||
enum class generation {
|
||||
nursery,
|
||||
tenured,
|
||||
N
|
||||
};
|
||||
|
||||
constexpr std::size_t gen2int(generation x) { return static_cast<std::size_t>(x); }
|
||||
|
||||
enum class generation_result {
|
||||
nursery,
|
||||
tenured,
|
||||
not_found
|
||||
};
|
||||
} /*namespace gc*/
|
||||
} /*namespace xo*/
|
||||
|
||||
/* end generation.hpp */
|
||||
Loading…
Add table
Add a link
Reference in a new issue