mnemosyne_arena/segment/pool/mod.rs
1//! Global segment caches: per-NUMA-node pools of retained segments and huge
2//! mappings, with cross-node stealing when the local node is empty.
3
4mod cache_aligned;
5pub mod huge_pool;
6pub mod list;
7mod node_huge_bucket;
8mod numa_bucket;
9pub mod segment_pool;
10mod tagged_stack;
11
12pub use huge_pool::GlobalHugePool;
13pub use list::NodeSegmentPool;
14pub use segment_pool::GlobalSegmentPool;
15
16/// Point-in-time snapshot of [`GlobalHugePool`] counters.
17///
18/// All fields are individually relaxed reads; not jointly consistent.
19#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
20pub struct HugePoolStats {
21 /// Huge blocks currently held in the warm cache.
22 pub retained_blocks: usize,
23 /// Total bytes of huge blocks in the warm cache.
24 pub retained_bytes: usize,
25}
26
27/// Point-in-time snapshot of [`GlobalSegmentPool`] telemetry counters.
28///
29/// All fields are individually monotone-non-decreasing relaxed reads;
30/// they are not jointly consistent (no single atomic snapshot).
31///
32/// `#[non_exhaustive]`: this snapshot has gained fields three times
33/// (`reset_segments`/`reset_calls`, `oom_retries`/`oom_retry_successes`) as
34/// telemetry grew, and will again — a growing counter set is exactly the
35/// forward-compatibility case the attribute exists for.
36#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
37#[non_exhaustive]
38pub struct SegmentPoolStats {
39 /// Segments currently held in the warm cache.
40 pub retained: usize,
41 /// Cumulative segments returned to the OS by purge passes.
42 pub purged_segments: usize,
43 /// Cumulative purge-pass invocations.
44 pub purge_calls: usize,
45 /// Cumulative segments whose physical backing was dropped by a page-reset.
46 pub reset_segments: usize,
47 /// Cumulative reset-pass invocations.
48 pub reset_calls: usize,
49 /// Cumulative purge-and-retry attempts after a first OS allocation
50 /// failure (`allocate_segment`'s OOM recovery path).
51 pub oom_retries: usize,
52 /// Cumulative purge-and-retry attempts whose retried allocation
53 /// succeeded, a subset of `oom_retries`.
54 pub oom_retry_successes: usize,
55}
56
57/// Sealed trait module to protect architectural invariants.
58#[doc(hidden)]
59pub mod private {
60 pub trait Sealed {}
61}
62
63/// The trio of global pools owned by a single memory backend.
64///
65/// One `const`-constructible bundle replaces the per-backend triplet of
66/// separate statics: each backend owns exactly one `static BackendPools`,
67/// and [`HasSegmentPool`] exposes its three components through default
68/// accessor methods.
69pub struct BackendPools {
70 segment: GlobalSegmentPool,
71 orphan: GlobalSegmentPool,
72 huge: GlobalHugePool,
73}
74
75impl BackendPools {
76 /// Creates a bundle of three empty pools.
77 ///
78 /// Const-constructible so each backend can declare its pools as a single
79 /// `static`, preserving the distinct-per-backend isolation that separate
80 /// statics previously provided.
81 pub const fn new() -> Self {
82 Self {
83 segment: GlobalSegmentPool::new(),
84 orphan: GlobalSegmentPool::new(),
85 huge: GlobalHugePool::new(),
86 }
87 }
88}
89
90impl Default for BackendPools {
91 #[inline]
92 fn default() -> Self {
93 Self::new()
94 }
95}
96
97/// Implements [`private::Sealed`] and [`HasSegmentPool`] for a backend type,
98/// associating it with a named `static BackendPools` instance.
99///
100/// Each backend requires exactly 5 boilerplate lines; this macro eliminates
101/// the duplication across all 7 backends (35 → 7 lines + this definition).
102macro_rules! impl_has_segment_pool {
103 ($backend:ty, $pools_name:ident) => {
104 static $pools_name: BackendPools = BackendPools::new();
105 impl private::Sealed for $backend {}
106 impl HasSegmentPool for $backend {
107 #[inline(always)]
108 fn pools() -> &'static BackendPools {
109 &$pools_name
110 }
111 }
112 };
113}
114
115/// Trait associating a memory backend with its global pools.
116///
117/// Implementors provide a single [`HasSegmentPool::pools`] accessor returning
118/// their owned [`BackendPools`]; the individual pool accessors are supplied as
119/// default methods delegating to it.
120pub trait HasSegmentPool: mnemosyne_core::MemoryBackend + private::Sealed {
121 /// Returns this backend's pool bundle.
122 fn pools() -> &'static BackendPools;
123
124 /// Returns the global segment pool for this backend.
125 #[inline(always)]
126 fn global_segment_pool() -> &'static GlobalSegmentPool {
127 &Self::pools().segment
128 }
129
130 /// Returns the global orphan pool for this backend.
131 #[inline(always)]
132 fn global_orphan_pool() -> &'static GlobalSegmentPool {
133 &Self::pools().orphan
134 }
135
136 /// Returns the global huge allocation pool for this backend.
137 #[inline(always)]
138 fn global_huge_pool() -> &'static GlobalHugePool {
139 &Self::pools().huge
140 }
141}
142
143impl_has_segment_pool!(mnemosyne_backend::DefaultBackend, DEFAULT_BACKEND_POOLS);
144impl_has_segment_pool!(
145 mnemosyne_backend::MemoryBackendWrapper,
146 WRAPPER_BACKEND_POOLS
147);
148impl_has_segment_pool!(mnemosyne_backend::CudaUnifiedBackend, CUDA_BACKEND_POOLS);
149impl_has_segment_pool!(mnemosyne_backend::CudaDeviceBackend, CUDA_DEVICE_POOLS);
150impl_has_segment_pool!(mnemosyne_backend::CudaHbmBackend, CUDA_HBM_POOLS);
151impl_has_segment_pool!(mnemosyne_backend::CudaGddrBackend, CUDA_GDDR_POOLS);
152impl_has_segment_pool!(
153 mnemosyne_backend::CudaHostPinnedBackend,
154 CUDA_HOST_PINNED_POOLS
155);