diff --git a/src/allocator.rs b/src/allocator.rs index 820a685e..19fee217 100644 --- a/src/allocator.rs +++ b/src/allocator.rs @@ -1,5 +1,5 @@ pub use alloc::alloc::{GlobalAlloc, Layout}; -use core::sync::atomic::{AtomicUsize, Ordering}; +use core::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; use hal_core::{ boot::BootInfo, mem::{ @@ -8,15 +8,22 @@ use hal_core::{ }, PAddr, }; -use mycelium_alloc::buddy; +use mycelium_alloc::{buddy, bump}; +use mycelium_util::{fmt, math::Logarithm}; #[derive(Debug)] pub struct Allocator { + bump: bump::Alloc, allocator: buddy::Alloc<32>, + /// If true, only the bump region is active. + bump_mode: AtomicBool, allocating: AtomicUsize, deallocating: AtomicUsize, } +/// 1k is enough for anyone. +const BUMP_REGION_SIZE: usize = 1024; + #[derive(Debug, Copy, Clone)] pub struct State { pub(crate) allocating: usize, @@ -24,11 +31,16 @@ pub struct State { pub(crate) heap_size: usize, pub(crate) allocated: usize, pub(crate) min_size: usize, + pub(crate) bump_mode: bool, + pub(crate) bump_allocated: usize, + pub(crate) bump_size: usize, } impl Allocator { pub const fn new() -> Self { Self { + bump: bump::Alloc::new(), + bump_mode: AtomicBool::new(true), allocator: buddy::Alloc::new(32), allocating: AtomicUsize::new(0), deallocating: AtomicUsize::new(0), @@ -39,9 +51,12 @@ impl Allocator { State { allocating: self.allocating.load(Ordering::Acquire), deallocating: self.deallocating.load(Ordering::Acquire), + bump_mode: self.bump_mode.load(Ordering::Acquire), heap_size: self.allocator.total_size(), allocated: self.allocator.allocated_size(), min_size: self.allocator.min_size(), + bump_allocated: self.bump.allocated_size(), + bump_size: self.bump.total_size(), } } @@ -58,6 +73,9 @@ impl Allocator { let added = self.allocator.add_region(region).is_ok(); tracing::trace!(added); self.deallocating.fetch_sub(1, Ordering::Release); + if self.bump_mode.swap(false, Ordering::Release) { + tracing::debug!("disabled bump allocator mode"); + } } #[inline] @@ -70,7 +88,11 @@ unsafe impl GlobalAlloc for Allocator { #[inline] unsafe fn alloc(&self, layout: Layout) -> *mut u8 { self.allocating.fetch_add(1, Ordering::Release); - let ptr = GlobalAlloc::alloc(&self.allocator, layout); + let ptr = if self.bump_mode.load(Ordering::Acquire) { + GlobalAlloc::alloc(&self.bump, layout) + } else { + GlobalAlloc::alloc(&self.allocator, layout) + }; self.allocating.fetch_sub(1, Ordering::Release); ptr } @@ -78,7 +100,9 @@ unsafe impl GlobalAlloc for Allocator { #[inline] unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { self.deallocating.fetch_add(1, Ordering::Release); - GlobalAlloc::dealloc(&self.allocator, ptr, layout); + if !self.bump.owns(ptr) { + GlobalAlloc::dealloc(&self.allocator, ptr, layout); + } self.deallocating.fetch_sub(1, Ordering::Release); } } @@ -119,6 +143,55 @@ impl State { } } +impl fmt::Display for State { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let &Self { + allocating, + deallocating, + heap_size, + allocated, + min_size, + bump_mode, + bump_allocated, + bump_size, + } = self; + f.write_str("heap stats:\n")?; + writeln!(f, " {allocating} cores allocating")?; + writeln!(f, " {deallocating} cores deallocating")?; + + if bump_mode { + writeln!(f, " bump allocator mode only")?; + } else { + let digits = (heap_size).checked_ilog(10).unwrap_or(0) + 1; + let free = heap_size - allocated; + writeln!(f, "buddy heap:")?; + + writeln!(f, " {free:>digits$} B free", digits = digits)?; + + writeln!(f, " {heap_size:>digits$} B total", digits = digits)?; + writeln!(f, " {free:>digits$} B free", digits = digits)?; + writeln!(f, " {allocated:>digits$} B busy", digits = digits)?; + writeln!( + f, + " {min_size:>digits$} B minimum allocation", + digits = digits + )?; + } + + writeln!(f, "bump region:")?; + let bump_digits = (bump_size).checked_ilog(10).unwrap_or(0) + 1; + let bump_free = bump_size - bump_allocated; + + writeln!(f, " {bump_free:>digits$} B free", digits = bump_digits)?; + writeln!( + f, + " {bump_allocated:>digits$} B used", + digits = bump_digits + )?; + Ok(()) + } +} + #[cfg(test)] mod tests { use mycotest::*; diff --git a/src/arch/x86_64/oops.rs b/src/arch/x86_64/oops.rs index e47052aa..80c1dfb0 100644 --- a/src/arch/x86_64/oops.rs +++ b/src/arch/x86_64/oops.rs @@ -162,60 +162,29 @@ pub fn oops(oops: Oops<'_>) -> ! { // we were in the allocator, so dump the allocator's free list if oops.involves_allocator() { - use mycelium_util::math::Logarithm; - let crate::allocator::State { - allocating, - deallocating, - heap_size, - min_size, - allocated, - } = oops.alloc; + let alloc_state = oops.alloc; let mut writer = mk_writer.make_writer(); - if allocating > 0 { + if alloc_state.allocating > 0 { writeln!( &mut writer, - "...while allocating ({allocating} allocations in progress)!" + "...while allocating ({} allocations in progress)!", + alloc_state.allocating, ) .unwrap(); } - if deallocating > 0 { + if alloc_state.deallocating > 0 { writeln!( &mut writer, - "...while deallocating ({deallocating} deallocations in progress)!" + "...while deallocating ({} deallocations in progress)!", + alloc_state.deallocating ) .unwrap(); } writer.write_char('\n').unwrap(); - let digits = (heap_size).checked_ilog(10).unwrap_or(0) + 1; - writeln!(&mut writer, "heap stats:").unwrap(); - writeln!( - &mut writer, - " {heap_size:>digits$} B total", - digits = digits - ) - .unwrap(); - writeln!( - &mut writer, - " {allocated:>digits$} B busy", - digits = digits - ) - .unwrap(); - writeln!( - &mut writer, - " {:>digits$} B free", - heap_size - allocated, - digits = digits - ) - .unwrap(); - writeln!( - &mut writer, - " {min_size:>digits$} B minimum allocation", - digits = digits - ) - .unwrap(); + writeln!(&mut writer, "{alloc_state}").unwrap(); crate::ALLOC.dump_free_lists(); }