diff --git a/Makefile b/Makefile index 0414121..7087819 100644 --- a/Makefile +++ b/Makefile @@ -20,6 +20,9 @@ endif CARGO_BUILD_OPTS=$(CARGO_COMMON_OPTS) \ --target=../etc/$(ARCH)-$(MACH).json +ifeq ($(VERBOSE),1) +CARGO_BUILD_OPTS+=--features verbose +endif ifneq ($(MACH),) CARGO_BUILD_OPTS+=--features mach_$(MACH) endif diff --git a/kernel/src/dev/tty.rs b/kernel/src/dev/tty.rs index 6a87eba..744d6a1 100644 --- a/kernel/src/dev/tty.rs +++ b/kernel/src/dev/tty.rs @@ -61,6 +61,14 @@ pub trait TtyDevice: SerialDevice { let ring = self.ring(); let config = ring.config.lock(); + if byte == b'@' { + use crate::mem::phys; + let stat = phys::statistics(); + debugln!("Physical memory stats:"); + debugln!("{:#?}", stat); + return; + } + if byte == b'\r' && config.iflag.contains(TermiosIflag::ICRNL) { byte = b'\n'; } diff --git a/kernel/src/mem/phys/manager.rs b/kernel/src/mem/phys/manager.rs index 0b3fdc4..89709ec 100644 --- a/kernel/src/mem/phys/manager.rs +++ b/kernel/src/mem/phys/manager.rs @@ -1,4 +1,4 @@ -use super::{PageInfo, PageUsage}; +use super::{PageInfo, PageUsage, PageStatistics}; use crate::mem::{memcpy, memset, virtualize, PAGE_SIZE}; use crate::sync::IrqSafeSpinLock; use core::mem; @@ -10,10 +10,12 @@ pub unsafe trait Manager { fn free_page(&mut self, page: usize) -> Result<(), Errno>; fn copy_cow_page(&mut self, src: usize) -> Result; fn fork_page(&mut self, src: usize) -> Result; + fn statistics(&self) -> PageStatistics; // TODO status() } pub struct SimpleManager { pages: &'static mut [PageInfo], + stats: PageStatistics, base_index: usize, } impl SimpleManager { @@ -32,6 +34,14 @@ impl SimpleManager { } Self { base_index: base / PAGE_SIZE, + stats: PageStatistics { + available: 0, + kernel: 0, + kernel_heap: 0, + paging: 0, + user_private: 0, + filesystem: 0 + }, pages, } } @@ -39,6 +49,7 @@ impl SimpleManager { let page = &mut self.pages[self.page_index(addr)]; assert!(page.refcount == 0 && page.usage == PageUsage::Reserved); page.usage = PageUsage::Available; + self.stats.available += 1; } fn page_index(&self, page: usize) -> usize { @@ -56,11 +67,41 @@ impl SimpleManager { } Err(Errno::OutOfMemory) } + + fn update_stats_alloc(&mut self, pu: PageUsage, count: usize) { + let field = match pu { + PageUsage::Kernel => &mut self.stats.kernel, + PageUsage::KernelHeap => &mut self.stats.kernel_heap, + PageUsage::Paging => &mut self.stats.paging, + PageUsage::UserPrivate => &mut self.stats.user_private, + PageUsage::Filesystem => &mut self.stats.filesystem, + _ => panic!("TODO {:?}", pu), + }; + *field += count; + self.stats.available -= count; + } + + fn update_stats_free(&mut self, pu: PageUsage, count: usize) { + let field = match pu { + PageUsage::Kernel => &mut self.stats.kernel, + PageUsage::KernelHeap => &mut self.stats.kernel_heap, + PageUsage::Paging => &mut self.stats.paging, + PageUsage::UserPrivate => &mut self.stats.user_private, + PageUsage::Filesystem => &mut self.stats.filesystem, + _ => panic!("TODO {:?}", pu), + }; + *field -= count; + self.stats.available += count; + } } unsafe impl Manager for SimpleManager { fn alloc_page(&mut self, pu: PageUsage) -> Result { - self.alloc_single_index(pu) - .map(|r| (self.base_index + r) * PAGE_SIZE) + let res = self.alloc_single_index(pu) + .map(|r| (self.base_index + r) * PAGE_SIZE); + if res.is_ok() { + self.update_stats_alloc(pu, 1); + } + res } fn alloc_contiguous_pages(&mut self, pu: PageUsage, count: usize) -> Result { 'l0: for i in 0..self.pages.len() { @@ -75,6 +116,7 @@ unsafe impl Manager for SimpleManager { page.usage = pu; page.refcount = 1; } + self.update_stats_alloc(pu, count); return Ok((self.base_index + i) * PAGE_SIZE); } Err(Errno::OutOfMemory) @@ -83,6 +125,7 @@ unsafe impl Manager for SimpleManager { let index = self.page_index(addr); let page = &mut self.pages[index]; + let usage = page.usage; assert!(page.usage != PageUsage::Reserved && page.usage != PageUsage::Available); if page.refcount > 1 { @@ -92,6 +135,10 @@ unsafe impl Manager for SimpleManager { page.usage = PageUsage::Available; page.refcount = 0; } + + drop(page); + self.update_stats_free(usage, 1); + Ok(()) } @@ -130,6 +177,10 @@ unsafe impl Manager for SimpleManager { } Ok(src) } + + fn statistics(&self) -> PageStatistics { + self.stats.clone() + } } pub(super) static MANAGER: IrqSafeSpinLock> = IrqSafeSpinLock::new(None); diff --git a/kernel/src/mem/phys/mod.rs b/kernel/src/mem/phys/mod.rs index 4a395ac..38e541c 100644 --- a/kernel/src/mem/phys/mod.rs +++ b/kernel/src/mem/phys/mod.rs @@ -32,6 +32,16 @@ pub enum PageUsage { Filesystem, } +#[derive(Clone, Debug)] +pub struct PageStatistics { + available: usize, + kernel: usize, + kernel_heap: usize, + paging: usize, + user_private: usize, + filesystem: usize, +} + /// Data structure representing a single physical memory page pub struct PageInfo { refcount: usize, @@ -66,18 +76,57 @@ impl Iterator for SimpleMemoryIterator { } } +#[cfg(feature = "verbose")] +fn trace_alloc(loc: &core::panic::Location, pu: PageUsage, base: usize, count: usize) { + use crate::debug::Level; + println!( + Level::Debug, + "\x1B[36;1m[phys/alloc] {}:{} {:?} {:#x}..{:#x}\x1B[0m", + loc.file(), + loc.line(), + pu, + base, + base + count * PAGE_SIZE + ); +} + +#[cfg(feature = "verbose")] +fn trace_free(loc: &core::panic::Location, page: usize) { + use crate::debug::Level; + println!( + Level::Debug, + "\x1B[36;1m[phys/free] {}:{} {:#x}..{:#x}\x1B[0m", + loc.file(), + loc.line(), + page, + page + PAGE_SIZE + ); +} + /// Allocates a contiguous range of `count` physical memory pages. +#[cfg_attr(feature = "verbose", track_caller)] pub fn alloc_contiguous_pages(pu: PageUsage, count: usize) -> Result { - MANAGER + let res = MANAGER .lock() .as_mut() .unwrap() - .alloc_contiguous_pages(pu, count) + .alloc_contiguous_pages(pu, count); + #[cfg(feature = "verbose")] + if let Ok(base) = res { + trace_alloc(&core::panic::Location::caller(), pu, base, count); + } + res } /// Allocates a single physical memory page. +#[cfg_attr(feature = "verbose", track_caller)] pub fn alloc_page(pu: PageUsage) -> Result { - MANAGER.lock().as_mut().unwrap().alloc_page(pu) + let res = MANAGER.lock().as_mut().unwrap().alloc_page(pu); + #[cfg(feature = "verbose")] + if let Ok(base) = res { + trace_alloc(&core::panic::Location::caller(), pu, base, 1); + } + res } /// Releases a single physical memory page back for further allocation. @@ -85,10 +134,19 @@ pub fn alloc_page(pu: PageUsage) -> Result { /// # Safety /// /// Unsafe: accepts arbitrary `page` arguments +#[cfg_attr(feature = "verbose", track_caller)] pub unsafe fn free_page(page: usize) -> Result<(), Errno> { + #[cfg(feature = "verbose")] + { + trace_free(&core::panic::Location::caller(), page); + } MANAGER.lock().as_mut().unwrap().free_page(page) } +pub fn statistics() -> PageStatistics { + MANAGER.lock().as_ref().unwrap().statistics() +} + /// # Safety /// /// Unsafe: accepts arbitrary `page` arguments