#![no_std]
use core::alloc::{GlobalAlloc, Layout};
use mnemosyne_core::NUM_SIZE_CLASSES;
use mnemosyne_local::{thread_alloc_layout, thread_free_layout, thread_realloc};
pub use mnemosyne_backend::{
CudaDeviceBackend, CudaGddrBackend, CudaHbmBackend, CudaHostPinnedBackend, CudaUnifiedBackend,
MemoryBackendWrapper, is_cuda_available,
};
pub use mnemosyne_core::{AllocPolicy, StandardPolicy, options::MnemosyneOptions};
pub use mnemosyne_hardened::{HardenedPolicy, SecurePolicy};
#[cfg(feature = "branded")]
pub use mnemosyne_heap::{
BrandedBlock, BrandedBox, BrandedCell, BrandedVec, Heap, InvariantLifetime, ReallocError,
ReallocFailure, ThreadLocalToken, scope as branded_scope,
};
pub use mnemosyne_local::{LocalAllocatorSelector, SizeClassOccupancy, usable_size};
pub use mnemosyne_prof::{
disable_leak_detector, disable_profiling, dump_leaks, dump_profile, enable_leak_detector,
enable_profiling, is_leak_detector_enabled, is_profiling_enabled, register_alloc_hook,
register_free_hook,
};
#[inline]
pub fn get_options() -> MnemosyneOptions {
mnemosyne_core::options::get_options()
}
#[inline]
pub fn configure(options: MnemosyneOptions) {
let old_cadence =
mnemosyne_core::options::PURGE_CADENCE_MS.load(core::sync::atomic::Ordering::Acquire);
mnemosyne_core::options::set_options(options);
mnemosyne_local::mark_options_initialized();
if options.purge_cadence_ms > 0 && old_cadence == 0 {
mnemosyne_decay::init_decay_engine();
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct MemoryStats {
pub current_mapped_bytes: usize,
pub peak_mapped_bytes: usize,
pub map_calls: usize,
pub unmap_calls: usize,
pub page_reset_calls: usize,
pub page_reset_bytes: usize,
pub guard_install_calls: usize,
pub guard_install_bytes: usize,
pub retained_free_segments: usize,
pub max_retained_free_segments: usize,
pub retained_free_bytes: usize,
pub purged_segments: usize,
pub purge_calls: usize,
pub purged_bytes: usize,
pub reset_segments: usize,
pub reset_calls: usize,
pub retained_huge_blocks: usize,
pub retained_huge_bytes: usize,
pub current_thread_live_allocations: usize,
pub current_thread_owned_segments: usize,
pub cross_thread_reclaimed_blocks: usize,
pub page_refills: usize,
pub recycled_pages: usize,
pub fresh_pages: usize,
pub fresh_segments: usize,
pub orphan_segments_adopted: usize,
pub recycle_sweeps: usize,
pub size_class_occupancy: [SizeClassOccupancy; NUM_SIZE_CLASSES],
}
impl Default for MemoryStats {
fn default() -> Self {
Self {
current_mapped_bytes: 0,
peak_mapped_bytes: 0,
map_calls: 0,
unmap_calls: 0,
page_reset_calls: 0,
page_reset_bytes: 0,
guard_install_calls: 0,
guard_install_bytes: 0,
retained_free_segments: 0,
max_retained_free_segments: 0,
retained_free_bytes: 0,
purged_segments: 0,
purge_calls: 0,
purged_bytes: 0,
reset_segments: 0,
reset_calls: 0,
retained_huge_blocks: 0,
retained_huge_bytes: 0,
current_thread_live_allocations: 0,
current_thread_owned_segments: 0,
cross_thread_reclaimed_blocks: 0,
page_refills: 0,
recycled_pages: 0,
fresh_pages: 0,
fresh_segments: 0,
orphan_segments_adopted: 0,
recycle_sweeps: 0,
size_class_occupancy: [SizeClassOccupancy::default(); NUM_SIZE_CLASSES],
}
}
}
pub fn memory_stats_generic<B: mnemosyne_arena::HasSegmentPool + LocalAllocatorSelector<B>>()
-> MemoryStats {
let backend = mnemosyne_backend::backend_memory_stats();
let arena = mnemosyne_arena::arena_memory_stats::<B>();
let local = mnemosyne_local::thread_allocator_stats::<B>();
MemoryStats {
current_mapped_bytes: backend.current_mapped_bytes,
peak_mapped_bytes: backend.peak_mapped_bytes,
map_calls: backend.map_calls,
unmap_calls: backend.unmap_calls,
page_reset_calls: backend.page_reset_calls,
page_reset_bytes: backend.page_reset_bytes,
guard_install_calls: backend.guard_install_calls,
guard_install_bytes: backend.guard_install_bytes,
retained_free_segments: arena.retained_free_segments,
max_retained_free_segments: arena.max_retained_free_segments,
retained_free_bytes: arena.retained_free_bytes,
purged_segments: arena.purged_segments,
purge_calls: arena.purge_calls,
purged_bytes: arena.purged_bytes,
reset_segments: arena.reset_segments,
reset_calls: arena.reset_calls,
retained_huge_blocks: arena.retained_huge_blocks,
retained_huge_bytes: arena.retained_huge_bytes,
current_thread_live_allocations: local.current_thread_live_allocations,
current_thread_owned_segments: local.current_thread_owned_segments,
cross_thread_reclaimed_blocks: local.cross_thread_reclaimed_blocks,
page_refills: local.page_refills,
recycled_pages: local.recycled_pages,
fresh_pages: local.fresh_pages,
fresh_segments: local.fresh_segments,
orphan_segments_adopted: local.orphan_segments_adopted,
recycle_sweeps: local.recycle_sweeps,
size_class_occupancy: local.size_class_occupancy,
}
}
pub fn memory_stats() -> MemoryStats {
memory_stats_generic::<mnemosyne_backend::MemoryBackendWrapper>()
}
pub fn purge_generic<B: mnemosyne_arena::HasSegmentPool>() {
unsafe {
mnemosyne_arena::purge_segment_pool::<B>();
}
}
pub fn purge() {
purge_generic::<mnemosyne_backend::MemoryBackendWrapper>();
}
pub fn reset_generic<B: mnemosyne_arena::HasSegmentPool>() {
unsafe {
mnemosyne_arena::reset_segment_pool::<B>();
}
}
pub fn reset() {
reset_generic::<mnemosyne_backend::MemoryBackendWrapper>();
}
pub fn decay() {
mnemosyne_decay::decay_step();
}
pub struct Mnemosyne;
unsafe impl GlobalAlloc for Mnemosyne {
#[inline(always)]
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
unsafe {
thread_alloc_layout::<StandardPolicy, mnemosyne_backend::MemoryBackendWrapper>(
layout.size(),
layout.align(),
)
}
}
#[inline(always)]
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
unsafe {
thread_free_layout::<StandardPolicy, mnemosyne_backend::MemoryBackendWrapper>(
ptr,
layout.size(),
layout.align(),
)
}
}
#[inline(always)]
unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
unsafe {
thread_realloc::<StandardPolicy, mnemosyne_backend::MemoryBackendWrapper>(
ptr, layout, new_size,
)
}
}
}
pub struct MnemosyneAllocator<
P: AllocPolicy,
B: mnemosyne_arena::HasSegmentPool + LocalAllocatorSelector<B> = mnemosyne_backend::MemoryBackendWrapper,
>(core::marker::PhantomData<(P, B)>);
impl<P: AllocPolicy, B: mnemosyne_arena::HasSegmentPool + LocalAllocatorSelector<B>>
MnemosyneAllocator<P, B>
{
pub const fn new() -> Self {
Self(core::marker::PhantomData)
}
}
impl<P: AllocPolicy, B: mnemosyne_arena::HasSegmentPool + LocalAllocatorSelector<B>> Default
for MnemosyneAllocator<P, B>
{
fn default() -> Self {
Self::new()
}
}
unsafe impl<P: AllocPolicy, B: mnemosyne_arena::HasSegmentPool + LocalAllocatorSelector<B>>
GlobalAlloc for MnemosyneAllocator<P, B>
{
#[inline(always)]
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
unsafe { thread_alloc_layout::<P, B>(layout.size(), layout.align()) }
}
#[inline(always)]
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
unsafe { thread_free_layout::<P, B>(ptr, layout.size(), layout.align()) }
}
#[inline(always)]
unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
unsafe { thread_realloc::<P, B>(ptr, layout, new_size) }
}
}
pub mod scratch {
pub use mnemosyne_arena::scratch::*;
}