1#![no_std]
4
5use core::alloc::{GlobalAlloc, Layout};
6use mnemosyne_core::NUM_SIZE_CLASSES;
7use mnemosyne_local::{thread_alloc_layout, thread_free_layout, thread_realloc};
8
9pub use mnemosyne_backend::{
10 CudaDeviceBackend, CudaGddrBackend, CudaHbmBackend, CudaHostPinnedBackend, CudaUnifiedBackend,
11 MemoryBackendWrapper, is_cuda_available,
12};
13pub use mnemosyne_core::{AllocPolicy, StandardPolicy, options::MnemosyneOptions};
14pub use mnemosyne_hardened::{HardenedPolicy, SecurePolicy};
15#[cfg(feature = "branded")]
16pub use mnemosyne_heap::{
17 BrandedBlock, BrandedBox, BrandedCell, BrandedVec, Heap, InvariantLifetime, ReallocError,
18 ReallocFailure, ThreadLocalToken, scope as branded_scope,
19};
20pub use mnemosyne_local::{LocalAllocatorSelector, SizeClassOccupancy, usable_size};
21pub use mnemosyne_prof::{
22 disable_leak_detector, disable_profiling, dump_leaks, dump_profile, enable_leak_detector,
23 enable_profiling, is_leak_detector_enabled, is_profiling_enabled, register_alloc_hook,
24 register_free_hook,
25};
26
27#[inline]
29pub fn get_options() -> MnemosyneOptions {
30 mnemosyne_core::options::get_options()
31}
32#[inline]
39pub fn configure(options: MnemosyneOptions) {
40 let old_cadence =
41 mnemosyne_core::options::PURGE_CADENCE_MS.load(core::sync::atomic::Ordering::Acquire);
42 mnemosyne_core::options::set_options(options);
43 mnemosyne_local::mark_options_initialized();
44
45 if options.purge_cadence_ms > 0 && old_cadence == 0 {
46 mnemosyne_decay::init_decay_engine();
47 }
48}
49
50#[derive(Clone, Copy, Debug, Eq, PartialEq)]
52pub struct MemoryStats {
53 pub current_mapped_bytes: usize,
54 pub peak_mapped_bytes: usize,
55 pub map_calls: usize,
56 pub unmap_calls: usize,
57 pub page_reset_calls: usize,
60 pub page_reset_bytes: usize,
62 pub guard_install_calls: usize,
65 pub guard_install_bytes: usize,
67 pub retained_free_segments: usize,
68 pub max_retained_free_segments: usize,
69 pub retained_free_bytes: usize,
70 pub purged_segments: usize,
71 pub purge_calls: usize,
72 pub purged_bytes: usize,
73 pub reset_segments: usize,
77 pub reset_calls: usize,
79 pub retained_huge_blocks: usize,
82 pub retained_huge_bytes: usize,
85 pub current_thread_live_allocations: usize,
86 pub current_thread_owned_segments: usize,
87 pub cross_thread_reclaimed_blocks: usize,
88 pub page_refills: usize,
89 pub recycled_pages: usize,
90 pub fresh_pages: usize,
91 pub fresh_segments: usize,
92 pub orphan_segments_adopted: usize,
93 pub recycle_sweeps: usize,
94 pub size_class_occupancy: [SizeClassOccupancy; NUM_SIZE_CLASSES],
95}
96
97impl Default for MemoryStats {
98 fn default() -> Self {
99 Self {
100 current_mapped_bytes: 0,
101 peak_mapped_bytes: 0,
102 map_calls: 0,
103 unmap_calls: 0,
104 page_reset_calls: 0,
105 page_reset_bytes: 0,
106 guard_install_calls: 0,
107 guard_install_bytes: 0,
108 retained_free_segments: 0,
109 max_retained_free_segments: 0,
110 retained_free_bytes: 0,
111 purged_segments: 0,
112 purge_calls: 0,
113 purged_bytes: 0,
114 reset_segments: 0,
115 reset_calls: 0,
116 retained_huge_blocks: 0,
117 retained_huge_bytes: 0,
118 current_thread_live_allocations: 0,
119 current_thread_owned_segments: 0,
120 cross_thread_reclaimed_blocks: 0,
121 page_refills: 0,
122 recycled_pages: 0,
123 fresh_pages: 0,
124 fresh_segments: 0,
125 orphan_segments_adopted: 0,
126 recycle_sweeps: 0,
127 size_class_occupancy: [SizeClassOccupancy::default(); NUM_SIZE_CLASSES],
128 }
129 }
130}
131
132pub fn memory_stats_generic<B: mnemosyne_arena::HasSegmentPool + LocalAllocatorSelector<B>>()
134-> MemoryStats {
135 let backend = mnemosyne_backend::backend_memory_stats();
136 let arena = mnemosyne_arena::arena_memory_stats::<B>();
137 let local = mnemosyne_local::thread_allocator_stats::<B>();
138 MemoryStats {
139 current_mapped_bytes: backend.current_mapped_bytes,
140 peak_mapped_bytes: backend.peak_mapped_bytes,
141 map_calls: backend.map_calls,
142 unmap_calls: backend.unmap_calls,
143 page_reset_calls: backend.page_reset_calls,
144 page_reset_bytes: backend.page_reset_bytes,
145 guard_install_calls: backend.guard_install_calls,
146 guard_install_bytes: backend.guard_install_bytes,
147 retained_free_segments: arena.retained_free_segments,
148 max_retained_free_segments: arena.max_retained_free_segments,
149 retained_free_bytes: arena.retained_free_bytes,
150 purged_segments: arena.purged_segments,
151 purge_calls: arena.purge_calls,
152 purged_bytes: arena.purged_bytes,
153 reset_segments: arena.reset_segments,
154 reset_calls: arena.reset_calls,
155 retained_huge_blocks: arena.retained_huge_blocks,
156 retained_huge_bytes: arena.retained_huge_bytes,
157 current_thread_live_allocations: local.current_thread_live_allocations,
158 current_thread_owned_segments: local.current_thread_owned_segments,
159 cross_thread_reclaimed_blocks: local.cross_thread_reclaimed_blocks,
160 page_refills: local.page_refills,
161 recycled_pages: local.recycled_pages,
162 fresh_pages: local.fresh_pages,
163 fresh_segments: local.fresh_segments,
164 orphan_segments_adopted: local.orphan_segments_adopted,
165 recycle_sweeps: local.recycle_sweeps,
166 size_class_occupancy: local.size_class_occupancy,
167 }
168}
169
170pub fn memory_stats() -> MemoryStats {
172 memory_stats_generic::<mnemosyne_backend::MemoryBackendWrapper>()
173}
174
175pub fn purge_generic<B: mnemosyne_arena::HasSegmentPool>() {
177 unsafe {
180 mnemosyne_arena::purge_segment_pool::<B>();
181 }
182}
183
184pub fn purge() {
186 purge_generic::<mnemosyne_backend::MemoryBackendWrapper>();
187}
188
189pub fn reset_generic<B: mnemosyne_arena::HasSegmentPool>() {
197 unsafe {
201 mnemosyne_arena::reset_segment_pool::<B>();
202 }
203}
204
205pub fn reset() {
208 reset_generic::<mnemosyne_backend::MemoryBackendWrapper>();
209}
210
211pub fn decay() {
213 mnemosyne_decay::decay_step();
214}
215
216pub struct Mnemosyne;
221
222unsafe impl GlobalAlloc for Mnemosyne {
223 #[inline(always)]
226 unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
227 unsafe {
235 thread_alloc_layout::<StandardPolicy, mnemosyne_backend::MemoryBackendWrapper>(
236 layout.size(),
237 layout.align(),
238 )
239 }
240 }
241
242 #[inline(always)]
245 unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
246 unsafe {
249 thread_free_layout::<StandardPolicy, mnemosyne_backend::MemoryBackendWrapper>(
250 ptr,
251 layout.size(),
252 layout.align(),
253 )
254 }
255 }
256
257 #[inline(always)]
281 unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
282 unsafe {
283 thread_realloc::<StandardPolicy, mnemosyne_backend::MemoryBackendWrapper>(
284 ptr, layout, new_size,
285 )
286 }
287 }
288}
289
290pub struct MnemosyneAllocator<
295 P: AllocPolicy,
296 B: mnemosyne_arena::HasSegmentPool + LocalAllocatorSelector<B> = mnemosyne_backend::MemoryBackendWrapper,
297>(core::marker::PhantomData<(P, B)>);
298
299impl<P: AllocPolicy, B: mnemosyne_arena::HasSegmentPool + LocalAllocatorSelector<B>>
300 MnemosyneAllocator<P, B>
301{
302 pub const fn new() -> Self {
304 Self(core::marker::PhantomData)
305 }
306}
307
308impl<P: AllocPolicy, B: mnemosyne_arena::HasSegmentPool + LocalAllocatorSelector<B>> Default
309 for MnemosyneAllocator<P, B>
310{
311 fn default() -> Self {
312 Self::new()
313 }
314}
315
316unsafe impl<P: AllocPolicy, B: mnemosyne_arena::HasSegmentPool + LocalAllocatorSelector<B>>
317 GlobalAlloc for MnemosyneAllocator<P, B>
318{
319 #[inline(always)]
322 unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
323 unsafe { thread_alloc_layout::<P, B>(layout.size(), layout.align()) }
329 }
330
331 #[inline(always)]
334 unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
335 unsafe { thread_free_layout::<P, B>(ptr, layout.size(), layout.align()) }
338 }
339
340 #[inline(always)]
350 unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
351 unsafe { thread_realloc::<P, B>(ptr, layout, new_size) }
352 }
353}
354
355pub mod scratch {
357 pub use mnemosyne_arena::scratch::*;
358}