MemoryManager: correct initial memory use and add mdebug command

- Use seL4_Untyped_Describe to get an accurate view of each
  UntypedMemory slab being managed; this makes mstats reflect
  rootserver allocations.
- Track memory allocated before we run as "overhead" (was meant to
  track fragmentation but was always zero).
- Add an "mdebug" command to describe each managed memory slab;
  this is useful to see whether the kernel's view of memory use is
  consistent with MemoryManager.

Change-Id: I53b2738c430ad3356ecd16a1cad29ca92dc74beb
GitOrigin-RevId: 2ad43f9b7760c722a6590ea049a3814c8dcccba7
This commit is contained in:
Sam Leffler
2022-07-08 18:17:51 +00:00
parent a28057ea73
commit c2accc33b0
6 changed files with 76 additions and 7 deletions

View File

@@ -124,6 +124,7 @@ pub fn repl<T: io::BufRead>(
("kvwrite", kvwrite_command as CmdFn),
("install", install_command as CmdFn),
("loglevel", loglevel_command as CmdFn),
("mdebug", mdebug_command as CmdFn),
("mstats", mstats_command as CmdFn),
("ps", ps_command as CmdFn),
("start", start_command as CmdFn),
@@ -462,6 +463,18 @@ fn kvwrite_command(
Ok(())
}
fn mdebug_command(
_args: &mut dyn Iterator<Item = &str>,
_input: &mut dyn io::BufRead,
output: &mut dyn io::Write,
_builtin_cpio: &[u8],
) -> Result<(), CommandError> {
if let Err(status) = kata_memory_debug() {
writeln!(output, "stats failed: {:?}", status)?;
}
Ok(())
}
fn mstats(output: &mut dyn io::Write, stats: &MemoryManagerStats)
-> Result<(), CommandError>
{

View File

@@ -153,3 +153,13 @@ pub unsafe extern "C" fn memory_stats(
Err(e) => e.into(),
}
}
#[no_mangle]
pub unsafe extern "C" fn memory_debug() -> MemoryManagerError {
let recv_path = CAMKES.get_current_recv_path();
// NB: make sure noone clobbers the setup done in memory__init
CAMKES.assert_recv_path();
Camkes::debug_assert_slot_empty("memory_debug", &recv_path);
KATA_MEMORY.debug().into()
}

View File

@@ -317,6 +317,7 @@ pub trait MemoryManagerInterface {
fn alloc(&mut self, bundle: &ObjDescBundle) -> Result<(), MemoryError>;
fn free(&mut self, bundle: &ObjDescBundle) -> Result<(), MemoryError>;
fn stats(&self) -> Result<MemoryManagerStats, MemoryError>;
fn debug(&self) -> Result<(), MemoryError>;
}
// Public version of MemoryError presented over rpc interface.
@@ -692,3 +693,13 @@ pub fn kata_memory_stats() -> Result<MemoryManagerStats, MemoryManagerError> {
status => Err(status),
}
}
#[inline]
pub fn kata_memory_debug() -> Result<(), MemoryManagerError> {
extern "C" {
// NB: this assumes the MemoryManager component is named "memory".
fn memory_debug();
}
unsafe { memory_debug() };
Ok(())
}

View File

@@ -47,4 +47,7 @@ impl MemoryManagerInterface for KataMemoryManager {
fn stats(&self) -> Result<MemoryManagerStats, MemoryError> {
self.manager.lock().as_ref().unwrap().stats()
}
fn debug(&self) -> Result<(), MemoryError> {
self.manager.lock().as_ref().unwrap().debug()
}
}

View File

@@ -8,15 +8,21 @@ use kata_memory_interface::MemoryError;
use kata_memory_interface::MemoryManagerInterface;
use kata_memory_interface::MemoryManagerStats;
use kata_os_common::sel4_sys;
use log::{debug, error, warn, trace};
use log::{debug, error, info, warn, trace};
use smallvec::SmallVec;
use sel4_sys::seL4_CPtr;
use sel4_sys::seL4_CNode_Delete;
use sel4_sys::seL4_Error;
use sel4_sys::seL4_Result;
use sel4_sys::seL4_Word;
use sel4_sys::seL4_UntypedDesc;
use sel4_sys::seL4_Untyped_Describe;
use sel4_sys::seL4_Untyped_Retype;
use smallvec::SmallVec;
fn untyped_describe(cptr: seL4_CPtr) -> seL4_Untyped_Describe {
unsafe { seL4_Untyped_Describe(cptr) }
}
// SmallVec capacity for untyped memory slabs. There are two instances;
// one for anonymous memory and one for device-backed memory. The memory
@@ -63,6 +69,7 @@ pub struct MemoryManager {
total_bytes: usize, // Total available space
allocated_bytes: usize, // Amount of space currently allocated
requested_bytes: usize, // Amount of space allocated over all time
overhead_bytes: usize,
allocated_objs: usize, // # seL4 objects currently allocated
requested_objs: usize, // # seL4 objects allocated over all time
@@ -100,6 +107,7 @@ impl MemoryManager {
total_bytes: 0,
allocated_bytes: 0,
requested_bytes: 0,
overhead_bytes: 0,
allocated_objs: 0,
requested_objs: 0,
@@ -114,7 +122,15 @@ impl MemoryManager {
m._device_untypeds.push(UntypedSlab::new(ut, slots.start + ut_index));
} else {
m.untypeds.push(UntypedSlab::new(ut, slots.start + ut_index));
m.total_bytes += l2tob(ut.size_bits());
// NB: must get current state of ut as it will reflect resources
// allocated before we run.
let info = untyped_describe(slots.start + ut_index);
assert_eq!(info.sizeBits, ut.size_bits());
let size = l2tob(info.sizeBits);
// We only have the remainder available for allocations.
m.total_bytes += info.remainingBytes;
// Use overhead to track memory allocated out of our control.
m.overhead_bytes += size - info.remainingBytes;
}
}
// Sort non-device slabs by descending size.
@@ -138,6 +154,10 @@ impl MemoryManager {
pub fn total_requested_space(&self) -> usize {
self.requested_bytes
}
// Current allocated space out of our control.
pub fn overhead_space(&self) -> usize {
self.overhead_bytes
}
// Current allocated objects
pub fn allocated_objs(&self) -> usize {
@@ -254,7 +274,7 @@ impl MemoryManagerInterface for MemoryManager {
self.allocated_bytes -= size_bytes;
self.allocated_objs -= od.retype_count();
} else {
debug!("Undeflow on free of {:?}", od);
debug!("Underflow on free of {:?}", od);
}
}
}
@@ -265,9 +285,7 @@ impl MemoryManagerInterface for MemoryManager {
allocated_bytes: self.allocated_space(),
free_bytes: self.free_space(),
total_requested_bytes: self.total_requested_space(),
// TODO(sleffler): track fragmentation
// NB: assumes all heap usage is for the buddy allocator
overhead_bytes: 0,
overhead_bytes: self.overhead_space(),
allocated_objs: self.allocated_objs(),
total_requested_objs: self.total_requested_objs(),
@@ -276,4 +294,16 @@ impl MemoryManagerInterface for MemoryManager {
out_of_memory: self.out_of_memory(),
})
}
fn debug(&self) -> Result<(), MemoryError> {
// TODO(sleffler): only shows !device slabs
for ut in &self.untypeds {
let info = untyped_describe(ut.cptr);
let size = l2tob(info.sizeBits);
info!("[{}] allocated {} free {}", ut.cptr,
size - info.remainingBytes,
info.remainingBytes,
);
}
Ok(())
}
}

View File

@@ -4,4 +4,6 @@ procedure MemoryInterface {
MemoryManagerError alloc(in char request[]);
MemoryManagerError free(in char request[]);
MemoryManagerError stats(out RawMemoryStatsData data);
void debug();
};