Skip to main content

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}