mnemosyne_arena/segment/stats.rs
1//! Arena memory telemetry statistics types and helpers.
2
3use super::alloc::SEGMENT_MAPPING_SIZE;
4use super::pool::HasSegmentPool;
5
6/// Snapshot of arena-level segment cache state.
7#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
8pub struct ArenaMemoryStats {
9 pub retained_free_segments: usize,
10 /// Runtime retention cap currently enforced by the segment pool
11 /// (`mnemosyne_core::options::MAX_RETAINED_SEGMENTS`, clamped at set time
12 /// to the compile-time `MAX_RETAINED_SEGMENTS_LIMIT`), not the
13 /// compile-time limit itself.
14 pub max_retained_free_segments: usize,
15 pub retained_free_bytes: usize,
16 pub purged_segments: usize,
17 pub purge_calls: usize,
18 pub purged_bytes: usize,
19 /// Number of segments whose physical backing was released by a
20 /// confirmed `page_reset` while the segment itself remained cached
21 /// in the retained pool.
22 pub reset_segments: usize,
23 /// Number of `reset_segment_pool` invocations.
24 pub reset_calls: usize,
25 /// Number of huge blocks currently retained in the huge-allocation cache
26 /// across all NUMA nodes.
27 pub retained_huge_blocks: usize,
28 /// Total bytes of huge blocks currently retained in the huge-allocation
29 /// cache across all NUMA nodes — typically the dominant share of retained
30 /// RSS.
31 pub retained_huge_bytes: usize,
32}
33
34/// Outcome of attempting to release a segment mapping.
35#[derive(Clone, Copy, Debug, Eq, PartialEq)]
36pub enum SegmentRelease {
37 /// The backend confirmed release of the OS mapping.
38 Released,
39 /// The backend reported release failure; ownership remains with the pool.
40 RetainedAfterFailure,
41}
42
43/// Returns the current arena segment cache counters.
44#[inline]
45pub fn arena_memory_stats<B: HasSegmentPool>() -> ArenaMemoryStats {
46 let pool = B::global_segment_pool();
47 let huge_pool = B::global_huge_pool();
48 let retained = pool.retained_count();
49 ArenaMemoryStats {
50 retained_free_segments: retained,
51 // The runtime option is the enforced cap (`try_push_retained` reads it
52 // per push); the compile-time limit is only its clamp ceiling.
53 max_retained_free_segments: mnemosyne_core::options::MAX_RETAINED_SEGMENTS
54 .load(core::sync::atomic::Ordering::Relaxed),
55 retained_free_bytes: retained * SEGMENT_MAPPING_SIZE,
56 purged_segments: pool.purged_count(),
57 purge_calls: pool.purge_call_count(),
58 purged_bytes: pool.purged_count() * SEGMENT_MAPPING_SIZE,
59 reset_segments: pool.reset_segments_count(),
60 reset_calls: pool.reset_call_count(),
61 retained_huge_blocks: huge_pool.retained_blocks(),
62 retained_huge_bytes: huge_pool.retained_bytes(),
63 }
64}