xo-procedure2 stack: + report-gc-object-ages() primitive
This commit is contained in:
parent
0137fe11cc
commit
a8536f89cb
13 changed files with 187 additions and 1 deletions
|
|
@ -155,6 +155,26 @@
|
|||
noexcept: true,
|
||||
attributes: [],
|
||||
},
|
||||
// bool report_object_ages(obj<AAllocator> report_mm, obj<AAllocator> error_mm, obj<AGCObject> * output);
|
||||
{
|
||||
name: "report_object_ages",
|
||||
doc: [
|
||||
"Report gc object ages, at discretion of collector implementation.",
|
||||
"Creates array of dictionaries using memory from @p report_mm.",
|
||||
"Each dictionary has keys n-live and bytes, indexed by object age.",
|
||||
"If unable to comply (e.g. oom), return runtime error allocated from @p error_mm.",
|
||||
"Avoiding obj<AGCObject> return type to avoid #include cycle",
|
||||
],
|
||||
return_type: "bool",
|
||||
args: [
|
||||
{type: "obj<AAllocator>", name: "report_mm"},
|
||||
{type: "obj<AAllocator>", name: "error_mm"},
|
||||
{type: "obj<AGCObject> *", name: "output"},
|
||||
],
|
||||
const: true,
|
||||
noexcept: true,
|
||||
attributes: [],
|
||||
},
|
||||
],
|
||||
nonconst_methods: [
|
||||
// bool install_type(const AGCObject & iface)
|
||||
|
|
|
|||
|
|
@ -83,6 +83,12 @@ Creates dictionary using memory from @p report_mm.
|
|||
If unable to comply (e.g. oom), return runtime error allocated from @p error_mm.
|
||||
Avoiding obj<AGCObject> return type to avoid #include cycle **/
|
||||
virtual bool report_object_types(Copaque data, obj<AAllocator> report_mm, obj<AAllocator> error_mm, obj<AGCObject> * output) const noexcept = 0;
|
||||
/** Report gc object ages, at discretion of collector implementation.
|
||||
Creates array of dictionaries using memory from @p report_mm.
|
||||
Each dictionary has keys n-live and bytes, indexed by object age.
|
||||
If unable to comply (e.g. oom), return runtime error allocated from @p error_mm.
|
||||
Avoiding obj<AGCObject> return type to avoid #include cycle **/
|
||||
virtual bool report_object_ages(Copaque data, obj<AAllocator> report_mm, obj<AAllocator> error_mm, obj<AGCObject> * output) const noexcept = 0;
|
||||
|
||||
// nonconst methods
|
||||
/** install interface @p iface for representation with typeseq @p tseq
|
||||
|
|
|
|||
|
|
@ -67,6 +67,7 @@ namespace mm {
|
|||
[[noreturn]] bool is_type_installed(Copaque, typeseq) const noexcept override { _fatal(); }
|
||||
[[noreturn]] bool report_statistics(Copaque, obj<AAllocator>, obj<AAllocator>, obj<AGCObject> *) const noexcept override { _fatal(); }
|
||||
[[noreturn]] bool report_object_types(Copaque, obj<AAllocator>, obj<AAllocator>, obj<AGCObject> *) const noexcept override { _fatal(); }
|
||||
[[noreturn]] bool report_object_ages(Copaque, obj<AAllocator>, obj<AAllocator>, obj<AGCObject> *) const noexcept override { _fatal(); }
|
||||
|
||||
// nonconst methods
|
||||
[[noreturn]] bool install_type(Opaque, const AGCObject &) override;
|
||||
|
|
|
|||
|
|
@ -70,6 +70,9 @@ namespace mm {
|
|||
bool report_object_types(Copaque data, obj<AAllocator> report_mm, obj<AAllocator> error_mm, obj<AGCObject> * output) const noexcept override {
|
||||
return I::report_object_types(_dcast(data), report_mm, error_mm, output);
|
||||
}
|
||||
bool report_object_ages(Copaque data, obj<AAllocator> report_mm, obj<AAllocator> error_mm, obj<AGCObject> * output) const noexcept override {
|
||||
return I::report_object_ages(_dcast(data), report_mm, error_mm, output);
|
||||
}
|
||||
|
||||
// non-const methods
|
||||
bool install_type(Opaque data, const AGCObject & iface) override {
|
||||
|
|
|
|||
|
|
@ -103,6 +103,9 @@ public:
|
|||
bool report_object_types(obj<AAllocator> report_mm, obj<AAllocator> error_mm, obj<AGCObject> * output) const noexcept {
|
||||
return O::iface()->report_object_types(O::data(), report_mm, error_mm, output);
|
||||
}
|
||||
bool report_object_ages(obj<AAllocator> report_mm, obj<AAllocator> error_mm, obj<AGCObject> * output) const noexcept {
|
||||
return O::iface()->report_object_ages(O::data(), report_mm, error_mm, output);
|
||||
}
|
||||
|
||||
// non-const methods (still const in router!)
|
||||
bool install_type(const AGCObject & iface) {
|
||||
|
|
|
|||
|
|
@ -60,6 +60,12 @@ namespace xo {
|
|||
std::uint64_t mkheader(std::uint64_t t,
|
||||
std::uint64_t a,
|
||||
std::uint64_t z) const noexcept {
|
||||
|
||||
// don't let age wrap around.
|
||||
// Expect std::min() to compile to cmov (no branch)
|
||||
//
|
||||
a = std::min(a, this->max_age());
|
||||
|
||||
uint64_t tseq_bits = (t << (age_bits_ + size_bits_)) & tseq_mask();
|
||||
uint64_t age_bits = (a << size_bits_) & age_mask();
|
||||
uint64_t size_bits = z & size_mask();;
|
||||
|
|
@ -75,12 +81,16 @@ namespace xo {
|
|||
return ((1ul << tseq_bits_) - 1) << (age_bits_ + size_bits_);
|
||||
}
|
||||
|
||||
std::uint64_t max_age() const noexcept {
|
||||
return ((1ul << age_bits_) - 1);
|
||||
}
|
||||
|
||||
std::uint64_t age_mask() const noexcept {
|
||||
// e.g.
|
||||
// 00 00 00 FF 00 00 00 00
|
||||
// with age_bits=8, size_bits=32
|
||||
//
|
||||
return ((1ul << age_bits_) - 1) << size_bits_;
|
||||
return this->max_age() << size_bits_;
|
||||
}
|
||||
|
||||
std::uint64_t size_mask() const noexcept {
|
||||
|
|
|
|||
|
|
@ -250,6 +250,19 @@ namespace xo {
|
|||
obj<AAllocator> error_mm,
|
||||
obj<AGCObject> * p_output) const noexcept;
|
||||
|
||||
/** Report per-age-bucket information as an array of dictionaries.
|
||||
* Scans to-space to count per-age statistics.
|
||||
* Each dictionary has keys "n-live" and "bytes".
|
||||
* Array index corresponds to object age.
|
||||
*
|
||||
* @p mm allocate stats from this allocator.
|
||||
* @p error_mm allocator for error reporting when out-of-memory.
|
||||
* @p p_output on exit @p *p_output contains stats array
|
||||
**/
|
||||
bool report_object_ages(obj<AAllocator> mm,
|
||||
obj<AAllocator> error_mm,
|
||||
obj<AGCObject> * p_output) const noexcept;
|
||||
|
||||
// ----- queries -----
|
||||
|
||||
/** introspection for memory use.
|
||||
|
|
|
|||
|
|
@ -71,6 +71,12 @@ Creates dictionary using memory from @p report_mm.
|
|||
If unable to comply (e.g. oom), return runtime error allocated from @p error_mm.
|
||||
Avoiding obj<AGCObject> return type to avoid #include cycle **/
|
||||
static bool report_object_types(const DX1Collector & self, obj<AAllocator> report_mm, obj<AAllocator> error_mm, obj<AGCObject> * output) noexcept;
|
||||
/** Report gc object ages, at discretion of collector implementation.
|
||||
Creates array of dictionaries using memory from @p report_mm.
|
||||
Each dictionary has keys n-live and bytes, indexed by object age.
|
||||
If unable to comply (e.g. oom), return runtime error allocated from @p error_mm.
|
||||
Avoiding obj<AGCObject> return type to avoid #include cycle **/
|
||||
static bool report_object_ages(const DX1Collector & self, obj<AAllocator> report_mm, obj<AAllocator> error_mm, obj<AGCObject> * output) noexcept;
|
||||
|
||||
// non-const methods
|
||||
/** install interface @p iface for representation with typeseq @p tseq
|
||||
|
|
|
|||
|
|
@ -529,6 +529,87 @@ namespace xo {
|
|||
return ok;
|
||||
}
|
||||
|
||||
bool
|
||||
DX1Collector::report_object_ages(obj<AAllocator> mm,
|
||||
obj<AAllocator> error_mm,
|
||||
obj<AGCObject> * p_output) const noexcept
|
||||
{
|
||||
scope log(XO_DEBUG(true));
|
||||
|
||||
(void)error_mm;
|
||||
|
||||
std::uint64_t n_age = config_.arena_config_.header_.max_age() + 1;
|
||||
|
||||
// stats, indexed by age
|
||||
DArray * stats_v = DArray::empty(mm, n_age);
|
||||
|
||||
if (!stats_v)
|
||||
return false;
|
||||
|
||||
// pre-populate with empty dictionaries for each age bucket
|
||||
for (std::uint64_t a = 0; a < n_age; ++a) {
|
||||
DDictionary * recd = DDictionary::make(mm);
|
||||
|
||||
if (!recd)
|
||||
return false;
|
||||
|
||||
recd->upsert_cstr(mm, "age", DInteger::box(mm, a));
|
||||
recd->upsert_cstr(mm, "n-live", DInteger::box(mm, 0));
|
||||
recd->upsert_cstr(mm, "bytes", DInteger::box(mm, 0));
|
||||
|
||||
stats_v->push_back(obj<AGCObject,DDictionary>(recd));
|
||||
}
|
||||
|
||||
log && log(xtag("n_age", n_age),
|
||||
xtag("stats_v.size", stats_v->size()));
|
||||
|
||||
// scan to-space, count objects by age
|
||||
|
||||
// track largest age with at least one object
|
||||
std::int64_t max_age_present = 0;
|
||||
|
||||
for (Generation g{0}; g < config_.n_generation_; ++g) {
|
||||
const DArena * arena = this->get_space(role::to_space(), g);
|
||||
|
||||
for (AllocInfo info : *arena) {
|
||||
if (info.is_forwarding_tseq()) {
|
||||
assert(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t age = info.age();
|
||||
size_t z = info.size();
|
||||
|
||||
if (static_cast<std::int64_t>(age) > max_age_present)
|
||||
max_age_present = age;
|
||||
|
||||
auto recd = obj<AGCObject,DDictionary>::from(stats_v->at(age));
|
||||
|
||||
assert(recd);
|
||||
|
||||
auto n_live_opt = recd->lookup_cstr("n-live");
|
||||
assert(n_live_opt);
|
||||
auto bytes_opt = recd->lookup_cstr("bytes");
|
||||
assert(bytes_opt);
|
||||
|
||||
if (n_live_opt && bytes_opt) {
|
||||
auto n_live_gco = obj<AGCObject,DInteger>::from(n_live_opt.value());
|
||||
auto bytes_gco = obj<AGCObject,DInteger>::from(bytes_opt.value());
|
||||
|
||||
n_live_gco->assign_value(n_live_gco->value() + 1);
|
||||
bytes_gco->assign_value(bytes_gco->value() + z);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// trim to only report ages up to max observed
|
||||
stats_v->resize(max_age_present + 1);
|
||||
|
||||
*p_output = obj<AGCObject,DArray>(stats_v);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
size_type
|
||||
DX1Collector::header2size(header_type hdr) const noexcept
|
||||
{
|
||||
|
|
|
|||
|
|
@ -63,6 +63,12 @@ namespace xo {
|
|||
return self.report_object_types(report_mm, error_mm, output);
|
||||
}
|
||||
|
||||
auto
|
||||
ICollector_DX1Collector::report_object_ages(const DX1Collector & self, obj<AAllocator> report_mm, obj<AAllocator> error_mm, obj<AGCObject> * output) noexcept -> bool
|
||||
{
|
||||
return self.report_object_ages(report_mm, error_mm, output);
|
||||
}
|
||||
|
||||
auto
|
||||
ICollector_DX1Collector::install_type(DX1Collector & self, const AGCObject & iface) -> bool
|
||||
{
|
||||
|
|
|
|||
|
|
@ -27,6 +27,10 @@ namespace xo {
|
|||
static DPrimitive_gco_0 * make_report_gc_object_types_pm(obj<AAllocator> mm,
|
||||
StringTable * stbl);
|
||||
|
||||
/** create primitive: report gc object-age statistics **/
|
||||
static DPrimitive_gco_0 * make_report_gc_object_ages_pm(obj<AAllocator> mm,
|
||||
StringTable * stbl);
|
||||
|
||||
/** create primitive: report gc location of a value **/
|
||||
static DPrimitive_gco_1_gco * make_gc_location_of_pm(obj<AAllocator> mm,
|
||||
StringTable * stbl);
|
||||
|
|
|
|||
|
|
@ -78,6 +78,34 @@ namespace xo {
|
|||
|
||||
}
|
||||
|
||||
// ----- report-gc-object-ages -----
|
||||
|
||||
obj<AGCObject>
|
||||
xfer_report_gc_object_ages(obj<ARuntimeContext> rcx)
|
||||
{
|
||||
if (rcx.collector()) {
|
||||
obj<AGCObject> stats;
|
||||
bool ok = rcx.collector().report_object_ages(rcx.allocator(), rcx.error_allocator(), &stats);
|
||||
|
||||
if (ok && stats)
|
||||
return stats;
|
||||
}
|
||||
|
||||
return DBoolean::box(rcx.allocator(), false);
|
||||
}
|
||||
|
||||
DPrimitive_gco_0 *
|
||||
GcPrimitives::make_report_gc_object_ages_pm(obj<AAllocator> mm,
|
||||
StringTable * stbl)
|
||||
{
|
||||
(void)stbl;
|
||||
|
||||
auto any_ty = DAtomicType::make(mm, Metatype::t_any());
|
||||
auto pm_ty = obj<AType,DFunctionType>(DFunctionType::_make(mm, any_ty));
|
||||
|
||||
return DPrimitive_gco_0::_make(mm, "report-gc-object-ages", pm_ty, &xfer_report_gc_object_ages);
|
||||
}
|
||||
|
||||
// ----- gc-location-of -----
|
||||
|
||||
obj<AGCObject>
|
||||
|
|
|
|||
|
|
@ -142,6 +142,11 @@ namespace xo {
|
|||
GcPrimitives::make_report_gc_object_types_pm(mm, stbl),
|
||||
flags & InstallFlags::f_generalpurpose));
|
||||
|
||||
ok = ok & (PrimitiveRegistry::install_aux
|
||||
(sink,
|
||||
GcPrimitives::make_report_gc_object_ages_pm(mm, stbl),
|
||||
flags & InstallFlags::f_generalpurpose));
|
||||
|
||||
ok = ok & (PrimitiveRegistry::install_aux
|
||||
(sink,
|
||||
GcPrimitives::make_gc_location_of_pm(mm, stbl),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue