mirror of
https://github.com/AmbiML/sparrow-kata-full.git
synced 2025-09-16 23:18:54 +00:00
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:
@@ -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>
|
||||
{
|
||||
|
@@ -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()
|
||||
}
|
||||
|
@@ -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(())
|
||||
}
|
||||
|
@@ -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()
|
||||
}
|
||||
}
|
||||
|
@@ -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(())
|
||||
}
|
||||
}
|
||||
|
@@ -4,4 +4,6 @@ procedure MemoryInterface {
|
||||
MemoryManagerError alloc(in char request[]);
|
||||
MemoryManagerError free(in char request[]);
|
||||
MemoryManagerError stats(out RawMemoryStatsData data);
|
||||
|
||||
void debug();
|
||||
};
|
||||
|
Reference in New Issue
Block a user