use crate::class;
use crate::segment::{FIRST_DATA_SPAN, NO_CLASS, SEGMENT_BYTES, SPANS_PER_SEGMENT};
use crate::class::SPAN_BYTES;
use crate::heap::Heap;
use crate::stats::Stats;
impl Heap {
#[must_use]
pub fn snapshot(&self) -> Stats {
let mut st = Stats { live: self.live_bytes, rounding: self.rounding_bytes, ..Stats::default() };
let mut seg = self.segments;
while !seg.is_null() {
let s = unsafe { &*seg };
st.mapped += SEGMENT_BYTES as u64;
st.segment_overhead += SPAN_BYTES as u64;
let parked = s.foreign_bytes.load(core::sync::atomic::Ordering::Relaxed) as u64;
let parked_live = s.foreign_live.load(core::sync::atomic::Ordering::Relaxed) as u64;
st.cache += parked;
st.live -= parked_live;
st.rounding -= parked - parked_live;
for ix in FIRST_DATA_SPAN..SPANS_PER_SEGMENT {
add_span(&mut st, &s.spans[ix]);
if s.spans[ix].class != NO_CLASS {
st.spans_assigned += 1;
}
}
seg = s.next;
}
st.span_free += self.claims_unused_bytes();
st
}
}
fn add_span(st: &mut Stats, meta: &crate::segment::SpanMeta) {
if meta.class == NO_CLASS {
st.hysteresis += SPAN_BYTES as u64;
return;
}
let slot = class::size_of(meta.class as usize) as u64;
for i in 0..u32::from(meta.high_water) {
if meta.is_live(i) {
continue;
}
let (pa, pb) = crate::pagemap::pages_of_slot(i, slot as usize);
let all_gone = (pa..=pb).all(|p| meta.discarded & (1u16 << p) != 0);
if all_gone {
st.returned += slot;
} else {
st.span_free += slot;
}
}
st.virgin += SPAN_BYTES as u64 - u64::from(meta.high_water) * slot;
}