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///
8/// `#[non_exhaustive]`: this snapshot has gained fields repeatedly as
9/// telemetry grew (huge-pool accounting, reset counters, and now
10/// `oom_retries`/`oom_retry_successes`) — a growing counter set is exactly
11/// the forward-compatibility case the attribute exists for.
12#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
13#[non_exhaustive]
14pub struct ArenaMemoryStats {
15 /// Free segments the pool currently holds for reuse.
16 pub retained_free_segments: usize,
17 /// Runtime retention cap currently enforced by the segment pool
18 /// (`mnemosyne_core::options::MAX_RETAINED_SEGMENTS`, clamped at set time
19 /// to the compile-time `MAX_RETAINED_SEGMENTS_LIMIT`), not the
20 /// compile-time limit itself.
21 pub max_retained_free_segments: usize,
22 /// Bytes mapped by the retained free segments
23 /// (`retained_free_segments * SEGMENT_MAPPING_SIZE`).
24 pub retained_free_bytes: usize,
25 /// Cumulative segments returned to the OS by purges.
26 pub purged_segments: usize,
27 /// Cumulative purge passes.
28 pub purge_calls: usize,
29 /// Bytes unmapped by those purges (`purged_segments * SEGMENT_MAPPING_SIZE`).
30 pub purged_bytes: usize,
31 /// Number of segments whose physical backing was released by a
32 /// confirmed `page_reset` while the segment itself remained cached
33 /// in the retained pool.
34 pub reset_segments: usize,
35 /// Number of `reset_segment_pool` invocations.
36 pub reset_calls: usize,
37 /// Number of huge blocks currently retained in the huge-allocation cache
38 /// across all NUMA nodes.
39 pub retained_huge_blocks: usize,
40 /// Total bytes of huge blocks currently retained in the huge-allocation
41 /// cache across all NUMA nodes — typically the dominant share of retained
42 /// RSS.
43 pub retained_huge_bytes: usize,
44 /// Cumulative purge-and-retry attempts `allocate_segment` made after a
45 /// first OS allocation failure (its OOM recovery path).
46 pub oom_retries: usize,
47 /// Cumulative purge-and-retry attempts whose retried allocation
48 /// succeeded, a subset of `oom_retries`.
49 pub oom_retry_successes: usize,
50}
51
52/// Outcome of attempting to release a segment mapping.
53#[derive(Clone, Copy, Debug, Eq, PartialEq)]
54pub enum SegmentRelease {
55 /// The backend confirmed release of the OS mapping.
56 Released,
57 /// The backend reported release failure; ownership remains with the pool.
58 RetainedAfterFailure,
59}
60
61/// Returns the current arena segment cache counters.
62#[inline]
63pub fn arena_memory_stats<B: HasSegmentPool>() -> ArenaMemoryStats {
64 let pool = B::global_segment_pool();
65 let huge_pool = B::global_huge_pool();
66 let retained = pool.retained_count();
67 ArenaMemoryStats {
68 retained_free_segments: retained,
69 // The runtime option is the enforced cap (`try_push_retained` reads it
70 // per push); the compile-time limit is only its clamp ceiling.
71 max_retained_free_segments: mnemosyne_core::options::MAX_RETAINED_SEGMENTS
72 .load(core::sync::atomic::Ordering::Relaxed),
73 retained_free_bytes: retained * SEGMENT_MAPPING_SIZE,
74 purged_segments: pool.purged_count(),
75 purge_calls: pool.purge_call_count(),
76 purged_bytes: pool.purged_count() * SEGMENT_MAPPING_SIZE,
77 reset_segments: pool.reset_segments_count(),
78 reset_calls: pool.reset_call_count(),
79 retained_huge_blocks: huge_pool.retained_blocks(),
80 retained_huge_bytes: huge_pool.retained_bytes(),
81 oom_retries: pool.oom_retry_count(),
82 oom_retry_successes: pool.oom_retry_success_count(),
83 }
84}